Displaying Desktop Reports
From Xojo Documentation
Contents
Once you have designed your report with the Report Layout Editor, you have to provide data for it to display. This is called the data set. Databases are commonly used as data sets for reports, but you can also use any data you want by using the Reports.DataSet interface.
Using a Database as a Data Set
It is simple to use a database as the data set. You get the data you want into a RecordSet. Then you can pass the RecordSet to the report for it to use as its data set. Here is an example:
// SELECT statement
Dim ps As New PrinterSetup
Dim rpt As New TeamReport
If rpt.Run(teamRecordSet, ps) Then
If rpt.Document <> Nil Then
// Save the document for
// the Canvas to display
mReportDocument = rpt.Document
End If
End If
Using Text as a Data Set
To use anything else as a data set for a report, such a text file, you create a custom class that implements the Reports.DataSet interface. This interface specifies these methods: EOF As Boolean, Field(Integer) As Variant, Field(String) As Variant, NextRecord As Boolean, Run, Type(String) As Integer.
In these methods, you fetch the specific data you need from your actual data source (perhaps a text or XML file) and then return the result or do the expected action.
As a simple example, you can put the team names in a string array and then create a class to work with this array. You have to supply the code for each method in the interface.
To start with, create a class and call it TeamDataSet. Add the Reports.DataSet interface to it. Now add the array to contain the team names as a property of this class:
Create a Constructor method for the class and initialize the array there:
Now you can begin implementing the interface methods. Start with NextRecord as it is the simplest. The NextRecord method is used to move the current array position, but before that can be implemented, another property to track the current array position is needed:
Now you can add the code to move the array position to the NextRecord method:
EOF is next. EOF should return True when there is no more data in the array and False if there is still data.
The above code checks if the current array position will be beyond the size of the array.
Moving along, the Type method is used to return the type of a specified field name. The array only has one field, the team name, so this method should check for the field name of “TeamName” and return its type, which is String. The type is indicated by the same integer value that specifies types when working with databases. For String, this is 5.
Note: You can find the complete table of data type values in the Database Operations topic.
The two Field methods are used to get the value for the specified field in the current array position. One Field method uses an integer field position and the other uses the field name. There is only one field, so that simplifies things.
For Field(String) As Variant:
The name is matched to what is specified for the DataField property for each ReportField in the Report Layout.
For Field(Integer) As Variant, have it use the previous code:
Lastly, you need to implement the Run method. This method is called to start the process of getting the data. It is also simple because all you need to do for this example is initialize the array position:
With this class in place, you can now use it with the Report.Run method to populate the report with your data:
Dim ps As New PrinterSetup
Dim rpt As New TeamReport
If rpt.Run(teamData, ps) Then
If rpt.Document <> Nil Then
// Save the document for
// the Canvas to display
mReportDocument = rpt.Document
End If
End If
Displaying the Report
The Report Layout Editor lets you design your reports, but there is no way to preview them without running your app. Reports are generated as pictures, so you can display them by running the report with the data set and then displaying the generated report in a Canvas. Of course since the report is a Picture, you can do anything you can do with a Picture as well, such as save it directly to a FolderItem or database.
The above examples show how to run the report and have a comment that the document is saved for the Canvas to display. In order to display the report, the Document for the report is saved to a property of the window:
The RBReportDocument class has a property to tell you how many pages are in the report (PageCount) and methods that are used to display, print and save the report (Page, Print, Save).
To display the report, you get one page at a time using the Page method (which returns a Picture containing the page of the report). You then use a Canvas to display the picture.
For example, this code in the Paint event of a Canvas displays page 1 of a report:
This code always only shows page 1 of the report. For an actual report preview, you usually display one page at a time and have Back/Next buttons to move between pages. The Back/Next buttons could alter a mCurrentDisplayPage property that you would use here in the Paint event in place of the “1” for the page number:
The PageCount property tells you how many pages there are in total.
Printing the Report
Printing a report works similarly to printing in general. You use PrinterSetup and OpenPrinter (or OpenPrinterDialog) to get a Graphics object. You then call the Print method of the Report Document to print it:
Dim ps As New PrinterSetup
Dim rpt As New TeamReport
If ps.PageSetupDialog Then
Dim g As Graphics
g = OpenPrinterDialog(ps)
If g <> Nil Then
If rpt.Run(teamRecordSet, ps) Then
If rpt.Document <> Nil Then
// Print the report
rpt.Document.Print(g)
End If
End If
End If
End If
Saving the Report
To save your report, you have a couple options. If you are using MacOS, you can let the user take advantage of its ability to print directly to a PDF file. The user can use the MacOS print dialog to select to save the report to a PDF file rather than sending it to the printer.
Your other choice is to save the Pictures to disk rather than drawing them on screen as this code shows:
Dim ps As New PrinterSetup
Dim rpt As New TeamReport
If rpt.Run(teamData, ps) Then
If rpt.Document <> Nil Then
Dim saveFolder As FolderItem
saveFolder = SelectFolder
If saveFolder <> Nil Then
Dim saveFile As FolderItem
For i As Integer = 1 To rpt.Document.PageCount
saveFile = saveFolder.Child("TeamReport" + Str(i) + ".png")
rpt.Document.Page(i).Save(saveFile, Picture.SaveAsPNG)
Next
End If
End If
End If
Example Projects
- Examples/Printing and Reporting/Reporting/GasReport/GasReport
- Examples/Printing and Reporting/Reporting/ListBoxReport
- Examples/Printing and Reporting/Reporting/Orders1/ListOfOrders
- Examples/Printing and Reporting/Reporting/Orders2/BreakingListOfOrders
- Examples/Printing and Reporting/Reporting/Products/List Of Products Preview
- Examples/Printing and Reporting/Reporting/Products/List Of Products
See Also
Reports module; Reports.DataSet interface; UserGuide:Framework, UserGuide:Report Layout Editor topics