Programming Gambas from Zip/Printing

Printing

edit

When practising printing, printing “to a file” will save paper. You can open the resulting PDF (Portable Document Format) file in your favourite PDF reader, such as Okular, and see on screen what you would get on paper.

This is about the simplest demonstration of printing. In your program you need a “printer”. We have used objects like buttons and tableviews. You can see them. A printer, though, is invisible. There is a printer class, just as there is a button class. You drag a printer onto your form just the same as you would drag a button or any other object. On the form it looks like a printer, but when the program runs it cannot be seen. It is really just a lump of code that is built into Gambas and does the things that printers are supposed to do, namely print and look after page sizes and orientation and so on. Printer is a clever little object.

First you tell your Printer object to configure, then you tell it to print. (“Printer, print!”, or as we write it in Gambas, prn1.print ). When you tell it to print it will issue the Draw event. In the draw event you put things on the page that you want printed. You do this with all the abilities that another class has, the Paint class. The Paint class can put things onto the page for printing, but it has other uses too, such as painting into DrawingAreas or ScrollAreas on the form. Right: here we go!

Printing Some Plain Text

edit

   

 

This small form has a Printer object and a button called bPlainPrint.

Public SimpleText As String

Public Sub Form_Open()

  SimpleText = "Countries of the World<br><br>Papua New Guinea<br><br>Papua New Guinea is a country that is north of Australia. It has much green rainforest. It has beautiful blue seas. Its capital, located along its southeastern coast, is Port Moresby.<br><br>This is plain text in Linux Libertine 12 point.<br><br>John Smith, editor"

End

Public Sub pr1_Draw()
  Paint.Font = Font["Linux Libertine,12"]
  Paint.DrawRichText(SimpleText, 960, 960, Paint.Width - 2 * 960)
End

Public Sub bPrintPlain_Click()
  If pr1.Configure() Then Return 'if user clicks Cancel, don't continue
  pr1.Print
End

When the form opens, some text is put in a variable called SimpleText for printing.

When the button is clicked the printer pr1 is told to configure itself. If the user clicks the Cancel button this returns the value of True, so we should do nothing more. Otherwise, dear friendly printer object, please print.

The printer object pr1 sends us the Draw event. It is saying, “I want to draw something! Please tell me what to paint on the page!”. We oblige by saying

Paint.Font = Font["Linux Libertine,12"]
Paint.DrawRichText(SimpleText, 960, 960, Paint.Width - 2 * 960)

Paint.Font is a property describing the font. It is a property with parts to it. We assemble those parts using Font[something]. The something is a string. For example, Font["Bitstream Vera Serif,Bold,24"] means “assemble a font that is Bitstream Vera Serif, bold, 24 point”. That is put in the Font property of the Paint thing. Actually the Paint thing is just a collection of skills. It is nothing you can see. It is another invisible class. Be careful not to put spaces in that string unless part of the font name. Gambas Help warns you of this. No spaces either side of the commas!

Paint.DrawRichText(something) is one of paint’s skills. It is a method it knows how to do. It needs at least three things in brackets. It can take a few more. Here we have four “arguments”, or “things in brackets”. First item: what to print. Second item: how far across to begin printing. Third item: how far down to begin printing. The 960 will give an inch margin. 96 dots per inch is a typical default printer resolution. The number is “tenths of a dot”. (I hope I have that right.) Fourth item: how wide is my printing going to be? Answer: the full width that Paint will allow less an inch on the left and an inch on the right. Each inch is 960. Take away two of them.

<br> means “break”, which goes to the next line. <br><br> means go to a new line, then go to a new line again. It gives us a blank line.

Rich Text understands <br>. It also understands quite a few other symbols planted in the text. There are symbols to make it print using “Heading 1” style, and “Heading 2” and so on. You cannot change what these styles look like, though. They are built in and that is that. You can also change fonts and print size and colour anywhere in your text. These codes make the print come out a certain way. In fact, it is a language in itself: HyperText Markup Language, or HTML. For example, to switch on Bold, put in this tag: <b>. When you want to switch Bold off, put in this one: </b>.

Printing Rich Text (with HTML tags in it)

edit

Instead of PlainText, get this to print:

FancyText = "<h3>Countries of the World</h3><Small>Papua New Guinea</Small><hr><br>Papua New Guinea is a country that is north of <font color = #780373><b>Australia</b>.</font><font color = black> It has much</font><font color = green> green rainforest</font><font color = black>. It has beautiful <font color = blue>blue seas</font><font color = black>. Its capital, located along its southeastern coast, is <Font Face=Times New Roman, Color=#FF0000>Port Moresby</font>.<br><br>This is written in <font face = Arial>HTML.<br></font><p align = right><font face = Times New Roman, Size=+1><b>John Smith</b></font>, <i>editor</i></p>"

Incidentally, that text, if saved in a text file with the extension .html, will open and display in a web browser, such as FireFox. You can try it.

The result will be:

 


I used Heading 3 ( <h3> … </h3> ) because Heading 1 was gross.

There are many tags in the text to make it look like that. Gambas allows these tags. It is only a small selection from the full HTML. Save a document in HTML in your word processor, open it in a text editor like Kate, and be amazed.

Tags that can be used in Rich Text

edit
<h1>, <h2>, <h3>, <h4>, <h5>, <h6> → Headlines <sup> → Superscript
<b> → Bold font <small> → Small
<i> → Italic <p> → Paragraph
<s> → Crossed out <br> → Line break
<u> → Underlined <a> → Link
<sub> → Subscript <font> → Font

Examples to change text colour and align a paragraph:

edit
<Font Color=#B22222> ... </Font> <p align=right> ... </p>
edit

   

 
Print.Configure( )

   

Drag a picture file onto the Data folder. Set the Picture property of the PictureBox to it.

The Printer is named pr1.

Public Pic As Picture

Public Sub pr1_Draw()
  Paint.DrawPicture(Pic, 960, 960, 3000, 3000)
End

Public Sub bPrint_Click()
  If pr1.Configure() Then Return 'if user clicks Cancel, don't continue
  Pic = PictureBox1.Picture
  pr1.Print
End

The picture is scaled to be 3000 x 3000. When I print to a file, the resolution is 96 dots per inch (96 dpi). The picture is printed 1 inch from the top and left margins and is scaled to fit into about 3 inches x 3 inches (3000x3000).

 

edit

 

In this program, 40 names are invented and put in an array called Z[]. If you were serious, the list of names could be typed in by the user or loaded from a names file or obtained from a database.

The names are printed down the page. There needs to be a side margin, and here it is set to an inch (960 dots when printing to PDF). It is stored in the variable (private property of the form) SideMargin. It is the same on the left and the right. The top margin is TopMargin.

When you print a name, how far down do you go before printing the next? LineSpacing is set to 280. That works out at about 0.3 of an inch. (960 is an inch).

The plan is: Print a name. However long that name is, move along a bit. That is the starting point for a horizontal line. Line as far as the page width less the right side margin. Draw the line. Go down a linespacing. Print the next name. Draw its line. Go down. Print a name. Draw its line, and so on.

Then draw the vertical lines to make the boxes. Start a little to the right of the width of the longest name. Step 330 dots, draw a vertical line, step another 330 dots, draw the next line, and so on. Don’t go past the end point of the horizontal lines. Finally, to make the right hand edge neat, draw a final vertical line. The Printer is called Prn. The button is bPrint.

   

 

Private z As New String[]
Private LineSpacing As Integer = 280
Private TopMargin As Integer = 960
Private SideMargin As Integer = 960

Public Sub Prn_Draw()

  Dim s As String
  Dim i As Integer
  Dim NameWidth, HowFarDown, MaxNameWidth, MaxDistanceDown As Float
  Dim MaxWidth As Float = Paint.Width - 2 * SideMargin

  Paint.Font = Font["Linux Libertine,12"]
  Paint.Color(Color.Black)
  Paint.MoveTo(SideMargin, TopMargin) 'start here
  Paint.LineTo(Paint.Width - SideMargin, TopMargin) 'draw to here
  Paint.Stroke 'paint the top line
  For i = 0 To z.Max
    s = z[i]
    NameWidth = Paint.TextExtents(s).Width + 180 'gap at the end about 1/5 inch
    MaxNameWidth = Max(MaxNameWidth, NameWidth) 'remember the width of the longest name
    HowFarDown = TopMargin + (LineSpacing * (i + 1))
    Paint.DrawText(s, SideMargin, HowFarDown)
    Paint.MoveTo(SideMargin + NameWidth, HowFarDown) 'starting position
    Paint.LineTo(Paint.Width - SideMargin, HowFarDown) 'finishing position
    Paint.Stroke 'draw the line
  Next
  MaxDistanceDown = TopMargin + z.Count * LineSpacing 'vertical lines go down to here
  For i = SideMargin + MaxNameWidth + 100 To Paint.Width - SideMargin Step 330 'step across the page every 1/3 inch
    Paint.MoveTo(i, TopMargin)
    Paint.LineTo(i, MaxDistanceDown)
    Paint.Stroke
  Next
  Paint.MoveTo(Paint.Width - SideMargin, TopMargin)
  Paint.LineTo(Paint.Width - SideMargin, MaxDistanceDown)
  Paint.Stroke 'final line on right

End

Public Sub GetNames()

  Dim FN As String[] = ["Oliver", "Jack", "Harry", "Jacob", "Charlie", "Thomas", "George", "Oscar", "James", "William", "Amelia", "Olivia", "Isla", "Emily", "Poppy", "Ava", "Isabella", "Jessica", "Lily", "Sophie"]
  Dim SN As String[] = ["Smith", "Jones", "Williams", "Brown", "Wilson", "Taylor", "Moreton", "White", "Martin", "Anderson", "Johnson", "Walsh", "Miller", "Davis", "Burns", "Murphy", "Lee", "Roberts", "Singh", "Evans"]

  FN.Shuffle
  SN.Shuffle
  Dim i, n As Integer
  For i = 1 To 40
    z.Add(FN[n] & " " & SN[n])
    n += 1
    If n > FN.Max Then
      FN.Shuffle
      SN.Shuffle
      n = 0
    Endif
  Next

End

Public Sub bPrint_Click()

  Prn.OutputFile = User.Home &/ "Names.pdf" 'I'm printing to a pdf file
  If Prn.Configure() Then Return
  GetNames
  Prn.Print()

End
edit

   

 

 

The form contains PictureBox1, a printer called Prn, and two buttons called bPicture and bPrint.

This program prints a calendar for the current month. When you look at the page you want to print you will see the “things” that have to be printed in various places. There are three things that call for repetition: the boxes, the numbers in the top left corner of each, and the names of the days of the week.

I gave PictureBox1 a default picture (that shows as soon as the program is run). First I dragged a photo onto the Data folder. Then I set the Picture property of the picturebox to it.

If you do not have a picture to begin with, the user needs to click the Choose Picture... button before clicking Print. The picture is stored in a property called Pic. If it is null printing does not proceed.

Public Pic As Picture

Public Sub LoadPicture()

  Dim Path As String

  Dialog.Title = "Please Select a picture"
  Dialog.Filter = ["*.jpg", "*.png", "Image Files", "*", "All files"]
  Dialog.Path = User.Home
  If Dialog.OpenFile() Then Return
  Pic = Picture.Load(Dialog.Path)
  PictureBox1.Picture = Pic

End

Public Sub bPicture_Click()
  LoadPicture
  FMain.SetFocus
End

Public Sub bPrint_Click()

  Pic = PictureBox1.Picture 'This line can be deleted if you don't give your PictureBox a default picture.
  If IsNull(Pic) Then
    Message("Please select a photo first.")
  Else
    Prn.OutputFile = User.Home &/ "Calendar.pdf"
    If Prn.Configure() Then Return
    Prn.Print
  Endif

End

Public Sub Prn_Draw()

  Dim LeftMargin As Float = 480 'half inch
  Dim TopMargin As Float = 1200 'inch and a bit
  Dim row, col, DayNum, CellNum As Integer
  Dim s As String
  Dim ThisMonth As Integer = Month(Date(Now)) 'the month number of the date part of the NOW function; 1 to 12
  Dim ThisYear As Integer = Year(Date(Now)) 'current year
  Dim FirstOfMonth As Date = Date(ThisYear, ThisMonth, 1)
  Dim StartDay As Integer = WeekDay(Date(FirstOfMonth)) 'the weekday of the first of the month
  Dim TextHeight, TextWidth, GridTop As Float

  GridTop = 7.2 * 960

  'Big Photo
  Paint.DrawPicture(Pic, LeftMargin, TopMargin / 2, Paint.Width - 2 * LeftMargin, 5 * 960) '5 inch height

  'Month and Year title
  Paint.Font = Font["Copperplate33bc,32"]
  TextHeight = Paint.TextExtents("S").Height 'the height of a character
  s = Choose(ThisMonth, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December") & " " & ThisYear
  Paint.DrawText(s, 0, GridTop - 1000, Paint.Width, TextHeight, Align.Center) 'inch above grid top

  'Grid
  Dim Side As Float = (Paint.Width - 2 * LeftMargin) / 7 'one-seventh of the width between margins
  For row = 0 To 4
    For col = 0 To 6
      Paint.DrawRect(LeftMargin + Side * Col, GridTop + Side * Row, Side, Side, Color.Black) 'each square
    Next
  Next

  'Days of the Week headings
  Paint.Font = Font["Apple Chancery,12"]
  TextHeight = Paint.TextExtents("S").Height 'the height of a character
  For col = 0 To 7
    s = Choose(col + 1, "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
    Paint.DrawText(s, LeftMargin + Side * Col, GridTop - TextHeight - 96, Side, TextHeight, Align.Center)
  Next

  'Dates
  Dim DaysInMonth As Integer
  If ThisYear Mod 4 = 0 And ThisMonth = 2 Then DaysInMonth = 29 Else DaysInMonth = Choose(ThisMonth, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  Paint.Font = Font["Linux Libertine,20"]
  TextHeight = Paint.TextExtents("1").Height 'the height of a digit
  For row = 0 To 4
    For col = 0 To 6
      CellNum = 7 * row + col
      If CellNum >= StartDay Then
        DayNum += 1
        If DayNum > DaysInMonth Then Return 'Don't go to 35 days in the month!
        s = If(Col = 0, "<font color=#DD0000>" & DayNum & "</Font>", "<font color=#000000>" & DayNum & "</Font>")
        Paint.DrawRichText(s, LeftMargin + Side * Col + 96, GridTop + Side * Row + TextHeight + 96)
      Endif
    Next
  Next
  Row = 0
  Col = 0
  While DayNum < DaysInMonth 'Put extra dates up in the top left of the grid.
    DayNum += 1
    s = If(Col = 0, "<font color=#DD0000>" & DayNum & "</Font>", "<font color=#000000>" & DayNum & "</Font>")
    Paint.DrawRichText(s, LeftMargin + Side * Col + 96, GridTop + Side * Row + TextHeight + 96)
    Col += 1 'next column
  Wend

End


Programming Gambas from Zip
 ← SQLite Printing Tray Icon Notebook →