Programming Gambas from Zip/Printing
Printing
[edit | edit source]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 | edit source]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 | edit source]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 | edit source]<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 | edit source]<Font Color=#B22222> ... </Font> | <p align=right> ... </p> |
Print an Image on a Page
[edit | edit source]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).
Print a Class List
[edit | edit source]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
Print a Calendar
[edit | edit source]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