Table of Contents
23.6.1.1 Print project
The text print project allows you to print simple text documents directly to printers or to a PDF or PostScript file.
23.6.1.1.1 Preliminary remarks - Notes
To print a document in Gambas, you must:
- first create a new Printer object,
- then call the Printer.Configure() method, which displays a printer configuration dialogue,
- then start the printing process by calling the Printer.Print() method and
- then draw the document page by page with Paint.
The print process is executed in a local event loop and the Print method only returns when the print process has been completed or cancelled. During this local event loop, the following events are triggered one after the other:
- Printer.Begin(),
- Printer.Paginate(),
- Printer.Draw() and
- Printer.End().
Only the Draw event must be implemented. All other events are optional.
Begin() event
This event is triggered when the print process starts. You can define the Printer.Count property there if you know exactly how many pages you have to print. Otherwise, you must implement the Paginate() event to layout your document and calculate the number of pages. By default, only one page is printed. Other important parameters such as the paper format and resolution can also be set in this event.
Paginate() event
This event is triggered so that you can add a page number to your document in the background. If you handle this event, the event handler is called again and again until you explicitly define the Count property. The calculation of the number of pages depends on what exactly you are drawing. If you are drawing text, you can use the Paint.TextSize() or Paint.RichTextSize() methods to calculate the size of elements such as the text height.
Please note: The Paginate() event also has nothing to do with the actual drawing. This only happens in the Draw event, which is called once for each page.
Draw() event
This event is called once for each page that needs to be printed. The complete drawing is done with the Paint class. The current page number is returned by the Printer.Page property. Each time the Draw event is triggered, a new page is created on the printer - except for the first one, which is created automatically.
Event End()
This event is triggered when the printing process is complete. The Paint.Begin() method is automatically called shortly before the Printer.Begin event and the Paint.End() method shortly after the Printer.End event. You therefore do not need to call them explicitly.
Margins
A page is drawn within a rectangle whose origin is (0, 0) and has the values Paint.Width and Paint.Height. These sizes apply if the Printer.FullPage property has been set to True. You should always print with this setting. The following text print project shows you how to provide a text page with freely defined margins for all four page margins and how to use the paper format to define the rectangle within which printing takes place.
Coordinates
Instead of the drawing coordinates in dots, you can also use coordinates in millimetres. To do this, you must use the Paint.Scale(Sx, Sy) method to scale the coordinate system so that each coordinate you specify has the unit millimetres. You can also use the Paint.Translate(Tx, Ty) method to move the coordinate origin of the coordinate system as required. The x-axis points to the right, but the y-axis points downwards!
The following source code sections show you how to draw three geometric shapes (rectangle, circle and line) and text with a defined font on a sheet of A4 paper and specify all coordinates in millimetres:
' Gambas class file Private CurPrinter As Printer Private LeftMargin As Integer = 20 '-- Dimensions in millimetres Private TopMargin As Integer = 20 Private Rightmargin As Integer = 15 Private BottomMargin As Integer = 20 Public Sub Form_Open() CurPrinter = New Printer As "CurPrinter" CurPrinter.Paper = Printer.A4 CurPrinter.FullPage = True CurPrinter.GrayScale = False CurPrinter.Resolution = 300 End Public Sub btnPrint_Click() If CurPrinter.Configure() = False Then CurPrinter.Print() Endif End Public Sub CurPrinter_Begin() Paint.Scale(Paint.Width / CurPrinter.PaperWidth, Paint.Height / CurPrinter.PaperHeight) Paint.Translate(LeftMargin, TopMargin) Paint.FontScale = (1 / (Paint.Height / CurPrinter.PaperHeight)) End Public Sub CurPrinter_Draw() Dim curX, curY, curW, curH As Float Dim curPrintH, curPrintW As Float Dim curText As String Paint.AntiAlias = True Paint.Font = Font["Monospace,10"] '-- Print Str(Paint.Font.Size * 0.353) & " mm" curPrintH = CurPrinter.PaperHeight - TopMargin - BottomMargin curPrintW = CurPrinter.PaperWidth - LeftMargin – RightMargin '-- Drawing a red rectangle curW = CurPrinter.PaperWidth - LeftMargin - RightMargin Paint.DrawRect(0, 0, curW, 100, Color.Red, 0.1) '-- Drawing a black circle Paint.Arc(curW / 2, 50, 40, 0, 2 * Pi, False) Paint.Stroke() '-- Drawing text curText = "»»» Drucken mit Gambas" curX = 0 curY = 170 curH = Paint.Font.Size * 0.353 curW = CurPrinter.PaperWidth - LeftMargin - RightMargin Paint.DrawText(curText, curX, curY, curW, curH, Align.Center) '-- Draw a thin blue line Paint.Brush = Paint.Color(Color.Blue) '-- Line color Paint.MoveTo(0, curPrintH) '-- Starting point of the line Paint.LineTo(curPrintW, curPrintH) '-- End point of the line Paint.LineWidth = 0.1 '-- Line width Paint.Stroke() '-- Paint the line End Public Sub CurPrinter_End() '-- NOOP End
Printer dialogue
Call up the printer dialogue and start printing
If CurPrinter.Configure() = False Then CurPrinter.Print() Endif
from Gambas show some special features under QT that you need to be aware of:
Figure 23.6.1.1.1: Printer dialogue
- The Properties> Pages> Orientation setting is adopted and realised when printing. The paper format is not adopted.
- In contrast, the Properties> Pages> Margins settings are ignored when printing because there appears to be no communication between the print dialogue and the Printer class.
- You can set the resolution (unit dpi) for direct printing under Properties> Advanced> General> Resolution. However, in the authors' experience, this setting in the printer dialogue does not change the definition Printer.Resolution = xy in the source text!
Font sizes
The unit of the font size, as returned by the Paint.Font.Size property, is the typographic point. A typographic point is 1/72 of an inch (0.353 mm) in size. So if a 10-point font is a good size for drawing text on the screen, it may be too large for printing on paper: Since the resolution of the printer is much larger than that of the screen, you usually print everything smaller.
If you use methods such as Paint.Scale(…), Paint.Translate(…) or Paint.Rotate(…), the font size is changed according to the paint matrix:
[1] Public Sub CurPrinter_Draw() [2] [3] Paint.Font = Font["Monospace,10"] [4] ... [5] End [6] [7] Public Sub CurPrinter_Begin() [8] [9] Paint.Scale(Paint.Width / CurPrinter.PaperWidth, Paint.Height / CurPrinter.PaperHeight) [10] Paint.Translate(LeftMargin, TopMargin) [11] Paint.FontScale = (1 / (Paint.Height / CurPrinter.PaperHeight)) [12] [13] End
Please note: The instructions in lines 3 and 11 ensure that you print exactly with the set font!
23.6.1.1.2 Text printing project
The project, which is based on ideas from the author Claus Dietrich, enables you to print simple text documents directly on printers or to print and save the content of the text documents in a PDF or PostScript file.
Essential properties, methods and events of the Printer class (gb.qt4/5) are used.
- You can select the file to be printed in a file selection dialogue and display the text in a text editor:
Figure 23.6.1.1.2: Programme interface
- You can change the text before printing. The changes are saved in the selected text file.
- It is printed on a DIN A4 page. The page format can only be changed in the source text.
- The text margins are predefined with fixed values, which have proven to be practical.
- However, you can change the pre-set print font in a font selection dialogue.
- Continuous text sections in the text are wrapped depending on the page margins and the specified print font. Hyphenation does not take place.
- Page numbering is not carried out using the paginate event, but by determining the total number of pages to be printed before printing.
- A print page contains a header with the name of the print file and the print date, followed by the page text content after a separator line. Each print page has a footer in which the current page number and the number of all print pages are displayed under a line in the format 'Page x of y'.
23.6.1.1.3 Text print project: Source text
The source text is displayed in full. Important procedures are then commented.
[1] ' Gambas class file [2] [3] Private $PrintFont As Font [4] Private $sFileName As String [5] Private $sCurText As String [6] Private $sCurFilePath As String [7] Private hPrinter As Printer [8] Private PageTexts As New String[] [9] [10] '-- All 6 of the following values have been tested in practice [11] Private LeftMargin As Integer = 20 ' In mm [12] Private Rightmargin As Integer = 15 [13] Private TopMargin As Integer = 15 [14] Private BottomMargin As Integer = 15 [15] Private HeaderMargin As Integer = 10 [16] Private FooterMargin As Integer = 10 [17] '----------------------------------- [18] [19] Private LMargin As Integer '-- In dots [20] Private TMargin As Integer [21] Private RMargin As Integer [22] Private BMargin As Integer [23] Private HMargin As Integer [24] Private FMargin As Integer [25] [26] [27] Public Sub Form_Open() [28] [29] Dim sMessage As String [30] [31] If Printer.List.Count = 0 Then ' True [32] sMessage = "<b><font size='+1', color='DarkRed'>" [33] sMessage &= ("PRINT MODE") [34] sMessage &= "</b></font><hr>" [35] sMessage &= "▶ " & ("No installed printer was detected.") & "<br>" [36] sMessage &= "▶ " & ("Printing to file only.") [37] Message.Error(sMessage) [38] cboxPrintToFile.Value = True [39] cboxPrintToFile.Enabled = False [40] Endif [41] [42] $PrintFont = Font["Liberation Mono,9"] '-- Default setting [43] bboxSetPrintFont.Text = $PrintFont.ToString() [44] [45] txtEditor.Font = Font["Monospace,12"] [46] txtEditor.Wrap = True [47] txtEditor.ShowLineNumber = True [48] txtEditor.ShowBraces = True [49] txtEditor.ShowCurrent = True [50] txtEditor.ShowPosition = True [51] [52] End [53] [54] Public Sub btnOpenText_Click() [55] [56] Dim sFilter As String [57] [58] lblFinish.Text = "" [59] [60] Dialog.Title = ("Select a plain-text file") [61] sFilter = "*.txt;*.html;*.sql;*.sh;*.js;*.css;*.c;*.c++;*.xml;*.class;*.webpage;*.gbs" [62] Dialog.Filter = [sFilter, ("Text files"), "*", ("All files")] [63] If Dialog.OpenFile(False) Then Return [64] $sCurFilePath = Dialog.Path [65] txtEditor.Text = File.Load(Dialog.Path) [66] $sCurText = txtEditor.Text [67] $sFileName = File.Name(Dialog.Path) [68] FMain.Caption = ("The text of the file is printed:") & " " & $sFileName [69] [70] End [71] [72] Public Sub txtEditor_Change() [73] $sCurText = txtEditor.Text [74] txtEditor.Save($sCurFilePath) [75] End [76] [77] Public Sub bboxSetPrintFont_Click() [78] [79] Dialog.Title = ("Select a print font") [80] Dialog.Font = Font["Liberation Mono,9"] '-- Default setting [81] If Dialog.SelectFont() Then Return [82] [83] $PrintFont = Dialog.Font [84] bboxSetPrintFont.Text = Dialog.Font.ToString() [85] [86] End [87] [88] Public Sub btnPrintText_Click() [89] [90] If $sCurText Then [91] lblFinish.Text = "" [92] With hPrinter = New Printer As "CurPrinter" [93] .Paper = Printer.A4 [94] .Resolution = 300 [95] .FullPage = True [96] End With [97] [98] If cboxPrintToFile.Value Then [99] Dialog.Title = ("Printing to file ...") [100] Dialog.Filter = ["*.pdf", "PDF file", "*.ps", "Post script file"] [101] Dialog.AutoExt = True [102] If Dialog.SaveFile() Then Return [103] hPrinter.OutputFile = Dialog.Path [104] hPrinter.Print() [105] Else [106] If hPrinter.Configure() = False Then [107] hPrinter.Print() [108] Endif [109] Endif [110] Endif [111] [112] End [113] [114] [115] Public Sub CurPrinter_Begin() [116] [117] Dim sFitPageText, sTextToPrint, sFullFitText As String [118] Dim hPaintExtents As PaintExtents [119] Dim iPages, curW, curH As Integer [120] [121] lblFinish.Text = "" [122] Paint.Font = $PrintFont [123] [124] LMargin = Paint.Width / hPrinter.PaperWidth * LeftMargin [125] TMargin = Paint.Width / hPrinter.PaperWidth * TopMargin [126] RMargin = Paint.Width / hPrinter.PaperWidth * RightMargin [127] BMargin = Paint.Width / hPrinter.PaperWidth * BottomMargin [128] [129] HMargin = Paint.Width / hPrinter.PaperWidth * HeaderMargin [130] FMargin = Paint.Width / hPrinter.PaperWidth * FooterMargin [131] [132] '-- Determine the number of pages - only possible via RichTextExtends [133] '-- TextExtends cannot be used [134] '-- Take not of the passed text, which converted to Rich-Text [135] curW = Paint.Width - LMargin - RMargin [136] hPaintExtents = Paint.RichTextExtents(Replace($sCurText, "\n", "<br>"), curW) [137] curH = Paint.Height - TMargin - HMargin - BMargin - FMargin [138] iPages = Ceil(hPaintExtents.Height / curH) + 1 '-- Add one page for safety [139] [140] '-- Generate a text which fits into the available width. Take note, that this text may have [141] '-- a lot of additional line breaks (LF)! The height is bigger than the number of expected [142] '-- pages to that the text fully fits into the avalable space. With this we get the full [143] '-- text with all addtional line-breaks. [144] [145] curW = Paint.W - LMargin - RMargin [146] curH = (Paint.H - TMargin - HMargin - BMargin - FMargin) * iPages [147] sFullFitText = Paint.TrimText($sCurText, curW, curH) [148] sTextToPrint = sFullFitText [149] [150] '-- Split the full text into separate pages [151] PageTexts.Clear() [152] Do [153] '-- Get the part of the text which fits in to one page [154] curW = Paint.W - LMargin - RMargin [155] curH = Paint.H - TMargin - HMargin - BMargin - FMargin [156] sFitPageText = Paint.TrimText(sTextToPrint, CurW, CurH) [157] '-- Add the text the PageTexts-Array [158] PageTexts.Add(sFitPageText) [159] '-- Cut the last page out of the full text [160] sTextToPrint = String.Right$(sTextToPrint, -String.Len(sFitPageText)) [161] '-- Repeat this until nothing is left to print [162] Loop Until sTextToPrint = "" [163] [164] '-- Set the total number of pages [165] hPrinter.Count = PageTexts.Count [166] [167] End [168] [169] Public Sub CurPrinter_Draw() [170] [171] Dim curX, curY, curW, curH As Integer [172] Dim sPrintText As String [173] [174] '-- HEADER-TEXT [175] Paint.Font = Font["Liberation Mono,9"] [176] curX = LMargin [177] curY = TMargin [178] curW = Paint.W - LMargin - RMargin [179] curH = HMargin [180] sPrintText = $sFileName [181] Paint.DrawText(sPrintText, curX, curY, curW, curH, Align.TopLeft) [182] sPrintText = Format(Now, "dddd - dd.mm.yyyy") [183] Paint.DrawText(sPrintText, curX, curY, curW, curH, Align.TopRight) [184] [185] '-- HEADER-LINE [186] curX = LMargin [187] curY = TMargin + (Paint.Width / hPrinter.PaperWidth) * 3.8 '-- mm [188] curW = Paint.W - RMargin [189] Paint.MoveTo(curX, curY) '-- Starting point of the line [190] Paint.LineTo(curW, curY) '-- End point of the line [191] Paint.LineWidth = 0.1 '-- Line width [192] Paint.Stroke() '-- Paint the line [193] [194] '-- CONTENT [195] '-- If the text fits the requested rectangle, it is returned as is. [196] '-- Otherwise it is trimmed and followed by an ellipsis character so that it fits. [197] '-- Remove "…" if found at the end of a page [198] If String.Right$(PageTexts[hPrinter.Page - 1], 1) = "…" Then [199] PageTexts[hPrinter.Page - 1] = String.Left$(PageTexts[hPrinter.Page - 1], -1) [200] Endif [201] Paint.Font = $PrintFont [202] curX = LMargin [203] curY = TMargin + HMargin [204] curW = Paint.W - LMargin - RMargin [205] curH = Paint.H - TMargin - HMargin - BMargin - FMargin [206] sPrintText = PageTexts[hPrinter.Page - 1] [207] Paint.DrawText(sPrintText, curX, curY, curW, curH) [208] [209] '-- FOOTER-LINE [210] curX = LMargin [211] curY = Paint.H - BMargin - (Paint.Width / hPrinter.PaperWidth) * 4.0 '-- mm [212] curW = Paint.W - RMargin [213] Paint.MoveTo(curX, curY) '-- Starting point of the line [214] Paint.LineTo(curW, curY) '-- End point of the line [215] Paint.LineWidth = 0.1 '-- Line width [216] Paint.Stroke() '-- Paint the line [217] [218] '-- FOOTER-TEXT [219] Paint.Font = Font["Liberation Mono,9"] [220] curX = LMargin [221] curY = Paint.H - FMargin - BMargin [222] curW = Paint.W - LMargin - RMargin [223] curH = HMargin [224] [225] sPrintText = ("Page") & " " & hPrinter.Page & " " & ("of") & " " & hPrinter.Count [226] Paint.DrawText(sPrintText, curX, curY, curW, curH, Align.BottomRight) [227] [228] End [229] [230] Public Sub CurPrinter_End() [231] lblFinish.Alignment = Align.Center [232] lblFinish.Text = " ▶ " & ("The text has been printed successfully!") [233] End [234] [235] Public Sub Form_Close() [236] [237] Dim hWindow As Window [238] [239] '-- Close all open windows [240] For Each hWindow In Windows [241] hWindow.Close() [242] Next [243] [244] End
Comment
- Lines 31 to 50 first check whether a printer is installed in the system, then the default font for the font selection dialogue is also specified. Finally, the essential properties of the editor for displaying the content of the selected text file are determined.
- You can select the file to be printed in a file selection dialogue in lines 60 to 68.
- You can change the set print font in lines 77 to 86 in a font selection dialogue.
- A new printer object is first created and configured in lines 88 to 112. If printing to a file has been activated, the text is 'printed' to a file. Otherwise, a dialogue for configuring a printer is called up and then the printout is started with the hPrinter.Print() method. The method returns False if the printout was successful.
- In the CurPrinter_Begin() event handling in lines 115 to 167, the margins are first converted from millimetres to XY (lines 124 to 133). Then the number of pages to be printed is calculated depending on the printable width and the specified print font.
- The individual pages are drawn in the curPrinter_Draw() event handling in lines 169 to 228. Anyone who works with Paint will notice this: The dedicated definition of curX, curY, curW, curH or curText before each drawing - primarily of text - is a good way to visualise exactly the rectangle that forms the container in which you want to draw the text.
- First, in lines 174 to 192 on each page, a header is drawn with the name of the print file (left-aligned) and the print date (right-aligned) as well as a separator line underneath.
- This is followed by the page text with the page number changed in each case, which is drawn in lines 194 to 207.
- Finally, a footer with the current page number and the number of all printed pages in the format 'Page x of y' is drawn in lines 209 to 226 on each page, flush right under a separator line.
Download
Chapter & Projects
download


