This class presents a report container that arranges its inserted controls vertically.
To create a new ReportVBox object in the source code:
Dim hReportVBox As ReportVBox hReportVBox = New ReportVBox ([ Parent As ReportContainer ])
You can then define the main style properties of the container.
Note: For many projects, it makes sense to specify the basic layout of the report in the IDE in the Report Designer. ReportVBoxes are part of the basic layout because in many cases they contain additional report control elements, which can then be inserted very easily via source code. This approach has proven itself in practice:
Figure 22.11.3.1.1: Report structure
The report structure shown in Figure 22.11.3.1.1 consists of a header as ReportPanel with two ReportLabels, the content area highlighted in yellow as ReportVBox and a footer as ReportPanel in section 1.
This class presents a report container that arranges its inserted controls horizontally.
To create a new ReportHBox object:
Dim hReportHBox As ReportHBox hReportHBox = New ReportHBox ( [ Parent As ReportContainer ] )
You can then define the main style properties of the ReportHBox container.
Example - the data basis is a database table
If hDBResult.Available Then For i = 0 To hDBResult.Max 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 = cMaxField["vorname"] rlblDBField.Text = hDBResult["vorname"] ... '-- EMail rlblDBField = New ReportLabel(rhboxDBRow) rlblDBField.Font = hDBFieldFont rlblDBField.Width = cMaxField["email"] rlblDBField.Text = hDBResult["email"] ... hDBResult.MoveNext() Next Endif
This is what a report section with alternating background for the data record looks like in the preview:
Figure 22.11.3.2.1: Section with three report HBoxes, each with nine ReportLabels
This class is a report container that arranges its inserted controls depending on the assigned value of the ‘Arrangement’ property. The default is ReportPanel.Arrangement = Arrange.None. However, the ‘Arrangement’ property can also have the values Arrange.Horizontal or Arrange.Vertical.
How to create a new ReportPanel object:
Dim hReportPanel As ReportPanel hReportPanel = New ReportPanel ( [ Parent As ReportContainer ] )
You can then define the main style properties of the container as in the following example:
Public Sub Report_Open() Report1.Padding = ReportPadding["10mm"] Report1.Spacing = "20mm" '-- Arrangement of 4 report labels one below the other ReportPanel1.Arrangement = Arrange.Vertical ReportPanel1.Spacing = "3mm" ReportPanel1.Padding = ReportPadding["Top:1mm;Bottom:1mm"] ReportPanel1.Height = "35mm" ' = (1+6+3+6+3+6+3+6+1)mm '-- Arrangement of 4 report labels next to each other ReportPanel2.Arrangement = Arrange.Horizontal ReportPanel2.Spacing = "3mm" ReportPanel2.Padding = ReportPadding["Top:1mm;Bottom:1mm"] ReportPanel2.Height = "8mm" ReportPanel2.Width = "45mm" ' =((210-2*10)-4*45)/3 '-- Utilisation of the effective width of 190 mm on the ReportPanel2 for a flush finish ReportLabel8.Expand = True ... End
Example:
Figure 22.11.3.3.1: Two report panels with 4 ReportLabels each in the Report Designer(!) in the IDE
Attention: Only after rendering do you see the real arrangement of the 8 report labels - either vertically (1-4) or horizontally (5-8) - in a preview:
Figure 22.11.3.3.2: Two report panels with 4 report labels each
This class reimplements the ‘Line’ class in the gb.qt5 component.
You define the line style using one of the following 6 line constants, whereby no line is drawn for the Line.None constant:
Example:
Public Sub Report_Open() Dim rLine As ReportLine Report1.Padding = ReportPadding["15mm"] rLineTop = New ReportLine (Report1) '-- TopLeft;Top;TopRight;Left;Right;BottomLeft;Bottom;BottomRight rLineTop.Direction = Align.Right '-- None;Solid;Dash;Dot;DashDot;DashDotDot rLineTop.LineStyle = Line.Dot '-- "m";"cm";"mm";"in";"pt";"px" rLineTop.LineWidth = "0.3mm" rLineTop.Brush = ReportBrush["#0000FF"] '-- Die Linie soll auf allen Seiten gezeichnet werden rLineTop.Fixed = True End
Attention: If you insert another line into the report, this line will adopt the line style of the first line defined! This also happens if you define its style separately. Obviously, this separate definition is ignored (as of 30 April 2023)!
It is worth considering setting a horizontal boundary with an upper and/or lower border of a report container instead of inserting a line into the report. The following is an example of using the container properties Border and Padding instead of a separate line.
'-- Inserting page numbers with format on each side rlblPageFooter.Fixed = True '-- Definition of selected properties rlblPageFooter.Border = ReportBorder["Top:0.1mm"] rlblPageFooter.Padding = ReportPadding["Top:1.3mm"] rlblPageFooter.Font = Font["Noto Sans,8"] rlblPageFooter.Height = GetTextHight(rlblPageFooter.Font) rlblPageFooter.Text = ("=\"Seite \" & (page) & \" von \" & (pages)") rlblPageFooter.Alignment = Align.Right
If you set the Report.ForceNewPage property to True, you force the creation of a new report page - but only if the content of a container does not fit completely on the page. In contrast, you can use the ReportPageBreak class, in which a new object forces a page break after a report control, which must be specified as a parameter.
Example
If you always want to start individual sections of a chapter on a new page for a text report, then you must insert a self-defined markup string such as <NewPage> in the original text and parse the text after it in order to create a new ReportPageBreak object.
Here is an excerpt from a text for a text report:
... 13 Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. <NewPage>25.2.4 Mirum est notare quam littera gothica 14 Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. ...
With regard to the markup string, you could, for example, insert <NewPage> or 2 dollar signs or other characters of your choice into the raw text and then parse the text when generating the structure of the report. Another idea would be equal signs as in the syntax of DokuWiki or # characters for MarkDown. You could also use the number of characters to control the text levels.
Dim rtlblText As ReportTextLabel Dim iHeight, iUsableWidth As Integer Dim sRawText As String Dim aLines As String[] Dim sLine As String Dim hTextFont As Font Dim rPageBreak As ReportPageBreak '-- Loading Text sRawText = File.Load("./data/lorem.txt") aLines = Split(sRawText, "\n") hTextFont = Font["Noto Sans,11"] iHeight = hTextFont.H iUsableWidth = GetUsableWidth() '-- Inserting text with many paragraphs For Each sLine In aLines '-- Each new chapter starts on a new page '-- Individual NewPage-Markup is <NewPage> in sRawText If Left(sLine, 9) = "<NewPage>" Then rPageBreak = New ReportPageBreak(rvboxText) sLine = Replace(sLine, "<NewPage>", "") Endif rtlblText = New ReportTextLabel(rvboxText) rtlblText.Font = hTextFont rtlblText.Alignment = Align.Justify rtlblText.Text = sLine rtlblText.Height = CStr(GetNumberOfRows(sLine, iUsableWidth, hTextFont) * iHeight) & "px" Next
Text in a report places special demands on the correct formatting of the text to be displayed in a ReportLabel or in a ReportTextLabel. Important to know: ReportTextLabels are the only labels that implement an (automatic) text wrap, which normal ReportLabels do not have.
The following scenarios occur:
With a headline consisting of a few words, you only need to make sure that the font is chosen so that the text fits on one line and matches the design.
If, on the other hand, you want to display data from a database table in a table in the report, you must ensure that a cell in your table - represented by a report label - is at least as long as the maximum length of the selected field. Of course, you must also take into account the font that you use for the report for the ReportLabel. You can use the following functions, which differ for SQLite, MySQL and PostgreSQL.
Use the following SQL statement to determine the maximum field length in a column (field_name) of an SQLite table (table_name):
SELECT max(length(field_name)) FROM table_name;
A special feature of SQLite is the determination of the maximum length for a date. Internally, a date is always saved as DateTime such as 08.12.1981 00: 00: 00 with an empty value for the time. In the procedure SetMaxTextWidth(argFont As Font) specified below, this special feature is taken into account.
The following SQL statement shows how to determine the maximum field length in a column of a MySQL table:
SELECT max( length( `field_name` ) ) AS `max_len` FROM `table_name`
This extended SQL statement for MySQL outputs the field content with the longest content:
SELECT field_name FROM table_name WHERE length(`field_name`) = SELECT max(length(`field_name`)) FROM table_name
For PostgreSQL, use this SQL statement to determine the maximum field length:
SELECT max(char_length(field_name)) FROM table_name
With this extended SQL statement for PostgreSQL, the field content with the longest content is output:
SELECT field_name FROM table_name WHERE char_length(field_name) = SELECT max(char_length(field_name)) FROM table_name
Notes
You must then permanently check whether the table header and all fields of the (DB) table are displayed for the font used. If, for example, only 7 ReportLabels fit into the container for a font used - in most cases this is a ReportVBox - then an existing 8th ReportLabel is simply cut off; it is simply no longer displayed in the container! Therefore, start with a very small font size, which you can gradually increase after a successful check using the Report.Preview() method.
Example: Calculation of the optimum width for each DB field (SQLite) in a report
Use the procedure SetMaxTextWidth(argFont As Font) to calculate the optimum width for each field ReportLabel for SQLite once, as a collection is created with the field names as the key and the maximum field length+3 as the value.
Private cMaxField As Collection Private sTablename As String = "contacts" ... Public Sub SetMaxTextWidth(argFont As Font) Dim hDBResultMax As Result Dim vValue As Variant For Each vValue In cMaxField '-- Special editing of the date in SQLite3 '-- Example of the stored date in the DB table: 08.12.1981 00: 00: 00 If cMaxField.Key = "gebdatum" Then sSQLStatement = Subst("Select date(&1), Max(Length(&1)) From &2", cMaxField.Key, DB.Quote(sTablename, True)) hDBResultMax = DBCS.DBConnection.Exec(sSQLStatement) cMaxField[cMaxField.Key] = CStr(argFont.TextWidth(hDBResultMax[0]) + 3) & "px" Else sSQLStatement = Subst("Select &1, Max(Length(&1)) From &2", cMaxField.Key, DB.Quote(sTablename, True)) hDBResultMax = DBCS.DBConnection.Exec(sSQLStatement) cMaxField[cMaxField.Key] = CStr(argFont.TextWidth(hDBResultMax[0]) + 3) & "px" Endif Next '-- To check: ' For Each vValue In cMaxField ' Print cMaxField.Key; " -> "; vValue ' Next End
Whether you increase the maximum size by 3 pixels - you can freely define the value within certain limits - or work with suitable values for padding (left/right) for the ReportLabel is up to you.
You can also insert page numbers in a footer that is to be displayed on certain or all pages of a report. It is informative to specify the current page number with a reference to the number of all pages of the report, such as ‘Page 3 of 6’. Please note that it is usual not to add a footer to an (optional) cover page.
When inserting page numbers, it depends on whether you insert the number of pages in the IDE in the properties in the corresponding report label in the footer or declare it in the source text, as the syntax is different.
Specifying page numbers in the Report Designer (IDE) for the text property of a report label in the footer:
="Page " & page & " von " & pages
Input in the source text in a ReportLabel ‘rlblPageFooter’:
'-- Inserting page numbers with format. rlblPageFooter.Fixed = True rlblPageFooter.Border = ReportBorder["Top:1px"] rlblPageFooter.Padding = ReportPadding["Top:3mm"] rlblPageFooter.Font = Font["Noto Sans,8"] rlblPageFooter.Height = GetTextHight(rlblPageFooter.Font) rlblPageFooter.Text = ("=\"Page \" & (page) & \" von \" & (pages)") rlblPageFooter.Alignment = Align.Left
If you are using a cover page, change the definition as follows
'-- Inserting page numbers with format. The cover sheet is NOT counted. rlblPageFooter.Text = ("=\"Page \" & (page -1) & \" von \" & (pages -1)")
You can check the selected layout and design of the report at any time via a report preview or a printout in order to make corrections. Temporarily setting the Report.Debug property to True can be a quick help here, because in this mode the borders and padding of all objects contained in the report are drawn in colour in the preview.
'-- Description of the structure of the report Public Sub Report_Open() ... '-- Only for controls in the testing of the report project Report.Debug = True ...
The Report.Refresh() method deletes all internal calculations and the current layout. You start the calculation of the layout with the Report.Layout() method. It can be called manually before printing, for example. But sometimes it is useful to calculate the layout in advance - for example for the preview. Both methods can be followed by rendering the report, which can be done on any medium (preview or printer) and in any resolution.
In many cases, it is necessary to print the generated report. Various report methods are available for this purpose:
The Report.Print() method immediately starts a dialogue without a report preview, in which you can set up the selected printer before printing and then print it:
Figure 22.11.3.10.1: Print dialogue
The Report.Preview() method is efficient. On the one hand, it allows you to check the report before printing and, on the other hand, offers output to the (standard) printer (Printer tab) with the option of specifying certain printer properties and, among other things, the print format (landscape or landscape format).
Alternatively, you can also print the report to a PDF file. Select the ‘File’ tab and start a dialogue to define the path and file name of the PDF file using the button box on the right-hand side of the line. Click on the Print button to start printing the report to the specified PDF file. This is great because you can then distribute this report file electronically, for example by email.
Figure 22.11.3.10.2: Printout in a PDF file (A4 landscape format)
To start a preview directly in the IDE. To do this, right-click on the ‘Report’ in the project directory and then select ‘Execute class’ in the context menu.
The Report.Print(hPrinter) method starts the printout immediately, as you have already created a printer object in the source code and provided it with suitable properties. This method is ideal if you always print with the same (standard) printer - without a preview and without a printer dialogue.
Dim hPrinter As Printer hPrinter = New Printer '-- Definition of selected printer properties hPrinter.Paper = Printer.A4 hPrinter.Orientation = Printer.Landscape hPrinter.GrayScale = True hPrinter.Duplex = Printer.Vertical Inc Application.Busy '-- The programme no longer accepts any input ... Report1.Print(hPrinter) '-- Printing is started Dec Application.Busy '-- The programme is accepting entries again...