This chapter presents 5 very different report projects:
Necessary considerations and preparatory work on how a printable report can be generated from a layout design have already been described in chapters 22.11.0 to 22.11.4.
For all report projects:
The complete source code for all 5 report projects is made available to you in a project archive - including the SQLite databases used.
For your own report projects, we recommend that you adapt the reports presented to your own requirements in terms of layout and design. For this reason, a detailed description has been omitted and reference is made to the corresponding source code of the 5 report projects. This note also applies to the report project in the following chapter 22.11.5.
The Report Designer is not used in the first report. Instead, the layout of the database report and the database data are drawn as text with the classes of the gb.cairo component on the CairoPdfSurface(argList) control element.
Figure 22.11.4.1.1: Database report (gb.cairo)
The report is drawn in the following procedure:
Private Sub Export2PDF() Dim PDFSurface As CairoPdfSurface Dim sPfadPDFDatei, sMessage As String Dim iDataSet As Integer '-- Initialization iCWidth = PDF_WIDTH - MARGIN_LEFT - MARGIN_RIGHT '-- Content-Width (Millimeter) iCHeight = PDF_HEIGHT - MARGIN_TOP - MARGIN_BOTTOM '-- Content-Height (Millimeter) iCurrentPage = 1 '-- Page number of the page (start) iCurrentTableRow = 1 '-- Number of table rows (start) fCurrentY = 0 '-- y-coordinate on the current page (start) sPfadPDFDatei = Application.Path &/ "kontakte.pdf" '-- DIN A4 - portrait format PDFSurface = New CairoPdfSurface(sPfadPDFDatei, PDF_WIDTH, PDF_HEIGHT) Cairo.Begin(PDFSurface) '-- Shift of the coordinate origin - >> Left = MARGIN_LEFT, Top = MARGIN_TOP Cairo.Matrix = Cairo.Matrix.Translate(MMToPoints(MARGIN_LEFT), MMToPoints(MARGIN_TOP)) Cairo.Matrix = Cairo.Matrix.Scale(1, 1) '-- Zoom factor = 1 Cairo.Font.Name = FONT_NAME '-- Provision of the DB data to be displayed in a DB result GetDBData() If resDBData.Count = 0 Then sMessage = "<font color='red'><center>The DB selection set is empty.</font>" sMessage &= "<hr>" sMessage &= "A DB report cannot be generated!</center>" Message.Warning(sMessage) Return Endif '-- Set record pointer to the first record resDBData.MoveTo(0) DrawHeader() DrawDatabaseInformation() DrawTableHeader() DrawTableRow() '-- Show first record DrawFooter() '-- DrawBorder() '-- Only for control purposes in testing '-- Draw all records (text) of the selected set For iDataSet = 1 To resDBData.Max If iCurrentPage = 1 Then If iCurrentTableRow = iPage1RowMax Then iCurrentPage = 2 iCurrentTableRow = 0 fCurrentY = 0 Cairo.ShowPage() '--DrawBorder() '-- Only for control purposes in testing DrawTableHeader() DrawFooter() Endif resDBData.MoveTo(iDataSet) DrawTableRow() Inc iCurrentTableRow Else If iCurrentTableRow = iPage2RowMax Then Inc iCurrentPage iCurrentTableRow = 0 fCurrentY = 0 Cairo.ShowPage() '-- DrawBorder() '-- Only for control purposes in testing DrawTableHeader() DrawFooter() Endif resDBData.MoveTo(iDataSet) DrawTableRow() Inc iCurrentTableRow Endif Next Cairo.End() '-- Preview DB Report Desktop.Open(sPfadPDFDatei) End
On each page, database report 2 consists of a header line, a separator line, the static table header, the individual database rows, another separator line and a footer line with the current page and details of all pages:
Figure 22.11.4.2.1: Report2 content 1st page
Database report 3 with a different layout to report 2, but with the same database, consists on each page of a header, a separator, the individual database rows after the initial, a further separator and a footer with the current page and details of all pages:
Figure 22.11.4.3.1: Report3 content of the last page
The following source code excerpt shows the creation of the capital letters (initials) in the procedure Set-Initial(sFirstChar) and the individual field contents within a data record. Please also note the generation of the different background colours (alternating) and the special format of the date of birth:
... sLastChar = "@" If hDBResult.Available Then For i = 0 To hDBResult.Max sFirstChar = Left(hDBResult["nachname"]) If Upper(sFirstChar) <> Upper(sLastChar) Then SetInitial(sFirstChar) iMod = i Mod 2 sLastChar = sFirstChar Endif rhboxDBRow = New ReportHBox(rvboxContent) rhboxDBRow.Spacing = "3mm" rhboxDBRow.Height = "6mm" rhboxDBRow.Padding = ReportPadding["1mm"] If iMod = 0 Then If i Mod 2 = 0 Then rhboxDBRow.BackGround = ReportBrush["#E0E0E0"] Else If i Mod 2 <> 0 Then rhboxDBRow.BackGround = ReportBrush["#E0E0E0"] Endif '-- SurName rlblDBField = New ReportLabel(rhboxDBRow) rlblDBField.Font = hDBFieldFont rlblDBField.Width = cMaxFieldLength[sTablename & "." & "vorname"] rlblDBField.Text = hDBResult["vorname"] '-- Name rlblDBField = New ReportLabel(rhboxDBRow) rlblDBField.Font = hDBFieldFont rlblDBField.Width = cMaxFieldLength[sTablename & "." & "nachname"] rlblDBField.Text = hDBResult["nachname"] ... '-- Birthday rlblDBField = New ReportLabel(rhboxDBRow) rlblDBField.Font = hDBFieldFont rlblDBField.Width = cMaxFieldLength[sTablename & "." & "gebdatum"] sDate = hDBResult["gebdatum"] rlblDBField.Text=Format(Date(Split(sDate,"-")[0],Split(sDate,"-")[1], Split(sDate,"-")[2]),"dd.mm.yyyy") hDBResult.MoveNext() Next Endif ... End ... Private Sub SetInitial(sArg As String) Dim rlblInitial As ReportLabel Dim rlblPlaceholder As ReportLabel Dim rhboxInitial As ReportHBox '-- Container: ReportHBox in container vbxReport rhboxInitial = New ReportHBox(rvboxContent) rhboxInitial.Spacing = "30mm" rhboxInitial.Margin.Top = "2mm" rhboxInitial.Height = "8mm" '-- Control ReportLabel in container ReportHBox rlblInitial = New ReportLabel(rhboxInitial) rlblInitial.Font.Name = "Sans Serif" rlblInitial.Font.Size = 12 rlblInitial.Font.Bold = True rlblInitial.BackGround = ReportBrush["#C3DDFF"] '-- Background: light blue '-- rlblInitial.BackGround = ReportBrush["LinearGradient(0,0,1,1,[#000000,#FFFFFF,#C3DDFF],[0,1,0.5])"] rlblInitial.Brush = ReportBrush.Color(&FF6347) '-- Forground: 'tomato' Favorite '-- rlblInitial.Brush = ReportBrush["Color(#FF6347)"] '-- Forground: 'tomato' '-- rlblInitial.Brush = ReportBrush["#FF6347"] '-- Forground: 'tomato' rlblInitial.Height = "8mm" ' fix rlblInitial.Width = "8mm" ' fix rlblInitial.Padding = ReportPadding["Top: 1px; Left:3px; Right:3px"] rlblInitial.Border = ReportBorder["Top:1px #7F7F7F;Bottom:1px #7F7F7F;Left:1px #7F7F7F; Right:1px #7F7F7F;TopLeftCorner:4mm;TopRightCorner:4mm;BottomRightCorner:4mm;BottomLeftCorner:4mm"] rlblInitial.Alignment = Align.Center rlblInitial.Text = Upper(sArg) '-- ReportLabel in container ReportHBox as a required placeholder (right) rlblPlaceholder = New ReportLabel(rhboxInitial) rlblPlaceholder.Expand = True End
In this special report 4, only text is displayed next to an image (with separator line). The (specially formatted) text is read from a text file. The special features of displaying text in a report have already been discussed in chapters 22.11.3.5 and 22.11.3.6. In this project, the theory described there is put into practice.
Figure 22.11.4.4.1: Text report
Notes
The following source code snippet shows tried and tested procedures for the correct display of text in a report:
'' The following procedures are only required to display the plain text Fast Private Function GetUsableWidth() As Integer ' If we use only the report padding, it is correct to subtract only the ' left and right padding of the book as here. ' But if we also use margins and/or padding of other containers and/or ' borders, these too must will be subtracted. Dim fReport, fLeft, fRight, fUsableWidth As Float '-- Conversion of report width from `cm` (default) to `mm` Report1.Width = Report1.UnitTo(GetValue(Report1.Width), "cm", "mm") & "mm" fReport = GetValue(Report1.Width) fRight = GetValue(Report1.Padding.Right) fLeft = GetValue(Report1.Padding.Left) fUsableWidth = Round(GetValue(Report1.UnitTo(fReport - (fLeft + fRight), "mm", "px")), 0) Return fUsableWidth Catch Error.Raise(("The value of measure can't be extracted")) End '' It is determined how many lines a text paragraph consists of. '' The value depends on the text paragraph, the space for a line '' in the text container 'ReportTextLabel' and the intended font. Fast Private Function GetNumberOfRows(argParagraph As String, argLineWidth As Integer, argFont As Font) As Integer Dim i, k As Integer Dim aWords As String[] Dim sRow, sWord As String '-- The text paragraph fits on one line If argFont.TextWidth(argParagraph) < argLineWidth Then Return 1 aWords = Split(argParagraph, " ") For Each sWord In aWords If k = 0 Then sRow &= sWord Inc k Else sRow &= " " & sWord Endif If argFont.TextWidth(sRow) > argLineWidth Then sRow = sWord Inc i k = 0 Endif Next Return i + 1 End Fast Private Function GetValue(argValue As String) As Float Return CFloat(Left(argValue, Len(argValue) - 2)) Catch Error.Raise(("The numerical value of the value cannot be determined")) End
Source code snippet for displaying the individual chapters and text sections in a chapter:
'-- Loading RawText '-- Static text - cannot be changed afterwards '-- sRawText = File.Load("./data/lorem.txt") '-- Dynamic text that can be changed afterwards sRawText = File.Load(Application.Path & "/data/lorem.txt") aParagraphs = Split(sRawText, "\n") iUsableWidth = GetUsableWidth() '-- Selected properties of rtlblText (Typ: ReportTextLabel) '-- Inserting text with many paragraphs For Each sParagraph In aParagraphs '-- Each new *chapter* starts on a new page '-- Individual NewPage-Markup <NewPage> in sRawText If Left(sParagraph, 9) = "<NewPage>" Then rPageBreak = New ReportPageBreak(rvboxText) sParagraph = Replace(sParagraph, "<NewPage>", "") Endif rtlblText = New ReportTextLabel(rvboxText) rtlblText.Font = Font["Noto Sans, 11"] rtlblText.Alignment = Align.Justify rtlblText.Text = sParagraph iHeight = rtlblText.Font.TextHeight(sParagraph) rtlblText.Height = CStr(GetNumberOfRows(sParagraph, iUsableWidth, rtlblText.Font) * iHeight) & "px" Next
Report 5 only uses the report component to display a line of text and an image. The image is a screenshot of the current window. The complete report source text is displayed:
' Gambas class file Private $hReport As Report Public Sub Form_Open() FMain.Resizable = False End Public Sub btnReportPreview_Click() GenerateReport() '-- Preview of the report and print dialogue $hReport.Preview() End Private Sub GenerateReport() Dim hReportLabel As ReportLabel Dim hReportImage As ReportImage Dim hScreenshotImage As Image $hReport = New Report $hReport.Padding = ReportPadding["2cm"] $hReport.Spacing = "7mm" '-- Printout: DIN A4 landscape format (default) $hReport.Paper = Printer.A4 $hReport.Orientation = Printer.Landscape hReportLabel = New ReportLabel($hReport) hReportLabel.Font.Size = 24 hReportLabel.Text = "Druck einer Bildschirm-Kopie (Screenshot)" hReportLabel.Autoresize = True hReportLabel.Alignment = Align.Center hReportLabel.Border = ReportBorder["Bottom:1px #606060;"] '-- The programme window is hidden FMain.Hide() Wait 0.2 '-- A screenshot of the complete, current desktop is created. hScreenshotImage = Desktop.Screenshot().Image '-- The programme window is displayed again FMain.Show() '-- A new ReportImage is created for the (current) report. hReportImage = New ReportImage($hReport) '-- The screenshot image is inserted into the report and configured hReportImage.Image = hScreenshotImage hReportImage.Autoresize = True hReportImage.Stretch = Report.Proportional hReportImage.Expand = True End
Figure 22.11.4.5.1: Report GUI
Figure 22.11.4.5.2: Report5 with a text line and an image