REALbasic Printing Tutorial – RSReport

Note:  RSReport is no longer available for sale.  This is here for legacy documentation.
If you’ve been in the Visual Basic world you’ll probably have heard about Crystal Reports. Crystal is THE reporting tool for the masses and, in fact, Microsoft includes Crystal Reports in every version of Visual Basic it sells. Most VB developers looking at Real Studio notice the omission of a reporting tool right away. While REAL Software includes a reporting tool, it’s not very good at anything other than the most lightweight of reporting needs.
RSReport from Roth Soft (http://www.rothsoft.ch/realbasic/rsreport) is a relative newcomer to reporting for Real Studio.  As of this writing, version 2010.2.3 is available and costs $86.  RSReport works in Real Studio 2008 Release 3 and newer (be aware that older versions of Real Studio might require older versions of RSReport).  The demo package contains all of the classes required to run a report.  The documentation is available online through Google docs so you can view in the language of your choice (via Google translation from German).
Using RSReport, reports can be generated from within any Real Studio application.  It is written in REALbasic so it’s fairly easy to pick up and understand how to use it.  Because it is up to the developer to pick and place elements on the page you have complete control over nearly all aspects of the reporting process.  RSReport also lets you export your reports to PDF with no fuss whatsoever.

The Project

We’ll take our printing project that we developed for the Graphic Object method we developed in Part 1 and instead of using the primitive graphics object method we’ll use RSReport.  From the demo project we’ll copy and past the Common and RSReport folders into our new project.  The Common folder contains subclassed controls used by the report viewer, various interfaces and modules.  The RSReport folder contains all of the items necessary for generating a report.
Download the project file:  RSReport Printing.zip

Creating the Report

The first thing you’ll want to do is add the PrintPreview container control to your window.    Since it’s a container control you get an idea fairly quickly of what the preview control will look like.  At the top of the preview control are a couple of controls that may, or may not be to your liking, but it’s possible to set their visibility and we’ll do that later.
The preview has a couple of events that are important.  The first is the OnChoiceLoad and lets you tell the control what reports are available.  For this sample, we’ll add just one report.  Add this in the cntPrintPreview1.open event:
  me.Choice_ClearReports
  me.Choice_Append “Sample Report”, “Sample Report”
 
When we run the project, the preview window is shown and there is one report in the report popup called “Sample Report”.  What we haven’t done yet is handle the preview controls OnReportBuild event.
Before we do that though, we’re going to create our own report.  Add a class to your project called MyReport that is a subclass of CRSRReport.  The important method you need to deal with is the Build method.  This method gets called when the report needs to be displayed (or printed if you’re doing direct printing).  In our build method we’re going to call our build method and then start creating our report.
You are responsible for determining when and where all report elements are created and placed.  If you want a report header, page headers and footers, grouping, etc. it’s all up to you.  This may seem daunting at first, but after your first one you’ll probably have a better feel for what you want (feel free to you the functions in the sample project!).  In the latest demo package from Roth Soft they have an another example of creating page headers and footers.
The basic object is the CRSRPrintElement and the subclasses for text, images, lines, ovals, rectangles, etc.  After you create it you set all the properties it needs.
In this updated example, we’ve created MyCompanyLayout which is a subclass of CRSRReport.  MyCompanyLayout takes care of  printing our headers and footers for us and allows us to reuse it for all of our reports.  Now we create a new subclass for each of our reports.  In this case we’ll create MyReport which is a subclass of MyCompanyLayout.
In our build method we’ll start by initializing some of variables and then call Super.Build so the super can initialize itself as well.  After the initialization we’ll call Build_MyReport which does a bulk of the heavy lifting.
Protected Sub Build()
  ‘Initialize MyCompanyReport
  msTitle = “Item Listing”
  msSubtitle = “(Subtitle)”
  super.Build
 
  ‘Build the contents of this report
  me.Build_MyReport
End Sub
Is the build method of MyCompanyLayout we set up our generic printing variables that we’ll be using later on.  Take a few minutes to take a look at the Build method in MyCompanyLayout.  Pay attention to the PageSetup function that determines the page orientation and size from the printer settings.  This perhaps is one of the weaker parts of RSReport is they only have support for A4, A5 and US Letter paper sizes.
We’ve also overridden the Page_AddNew method in MyCompanyLayout.  In the override we will automagically add a header and footer to each page.  This is nice because our subclass doesn’t have to deal with it.  We’ll also iterate through our elements on the elements and update the footer text that shows how many pages we have.
Back to our MyReport class we step into Build_MyReport which is where all of the real work is done.  We start by determining our page width and where our columns will be.
//Define our column-lefts (in percent)
Dim iPageWidthPixel As Integer
iPageWidthPixel = (giPrint_PageWidth – gdPrint_LeftBorder_Pixel – gdPrint_RightBorder_Pixel)
 
xCol1 = iPageWidthPixel * 0.2
xCol2 = iPageWidthPixel * 0.45
xCol3 = iPageWidthPixel * 0.2
xCol4 = iPageWidthPixel * 0.15
Then we get our recordset data.  If we have an error we gracefully exit from the report.
Now we’ll create a new page and setup our iY variable that controls where our ‘rows’ are placed.  We’ll also create a default font and give it our default font name and size.  This will cut down on code a bit.
 
me.Page_AddNew
dim iY as integer
 
dim s as string
dim oFont as new CRSRFont
oFont.FontName = “Arial”
oFont.FontSize = 10
 
iY = miHeaderBottom
Now here’s where the heavy lifting of the report really occurs.  We’ll start looping through our recordset until we get through them all.  We start, however, by creating a CRSRGroup to hold our row of data.
Dim oGroup As CRSRGroup
while mRS.EOF = false
    ‘Place the contents of the current record on a group
    oGroup = New CRSRGroup(0, 0)
We’ll keep track of the how tall each row is going to be so we can check to see if we’ve need to put it on another page.  We get our string from the recordset and then create a CRSRText object for each of our fields.
 
dim iLineHeight as integer   
‘the elements are place relative to the group…
s = Trim(mRS.Field(“sName”).StringValue)
oText1 = New CRSRText
oText1.text = s
oText1.Left_Pixel = iLineX + constBorder
oText1.Top_Pixel = constBorder
oText1.Font = oFont
oText1.WrapLines = true
oText1.Width_Pixel = xCol1 – 2*constBorder
//Convert text height to pixels because there is no TextHeight_Pixels
iLineHeight = max(iLineHeight, MMToPixel(oText1.TextHeight_MM))
iLineX = iLineX + xCol1 ‘go right
After we’ve done all of our fields we know how big our row is.  Then we can compare it to the top of our footer and if it will fall below it we immediate add a new page.  Keep in mind that our MyCompanyLayout class will automagically put in our header and footer.
In this updated example we now have the ability to add a grid and even shade the grid.  This gives the reports a nice look and adding it isn’t that hard.  All we have to do is create a CRSRRectangle and add it to the group BEFORE we add the oTextX objects (which contain the field data).
Finally we add the entire group to the page and add to our iY element.  Then we move to the next record in our recordset and repeat until there are no more records.
‘finally add the group to the page
me.Page_Last.Element_Add(oGroup)
‘and increase the top
iY = iY + iLineHeight
mRS.MoveNext
If you read the initial tutorial, this is considerably easier than the mental gyrations I was doing before.  Using the Group is a much easier and compact way of doing things.  However, in my own defense I was trying to learn from the original German documents.
At this point we need to populate the OnReportBuild event of the preview control.  Add this bit of code with simply returns an instance of your report.
  return new MyReport
Now run the project and clean up any errors you might have.  You should have something that looks like the screenshot below:
rsreport

More on Banded Reports

Earlier I talked about the difference between banded reports and what RSReport does.  While it’s true that RSReport is more work and it involved a heck of a lot of code it is incredibly more powerful than the average banded report generator.
If you run the demo application that comes with RSReport you’ll note that there is a sample page called “Grid Example.”  While this report seems straightforward using RSReport this is tough to do with banded reports.  In some it would be very difficult and in others you’d have to jump through some hoops.  Obviously it’s tradeoff between quick and easy and power.

What RSReport Is Missing

While I really like RSReport, the number of edit/debug cycles required to place your elements properly is very high.  It does have a report designer component that saves to a plain text file, but it’s tied so tightly with Roth Soft’s commercial product it’s very hard to integrate into your own project.
Roth Soft is selling a very good product and is quite a bargain in my opinion.  Unfortunately, they are also claiming to give no support to the product.  While I’ve had my questions answered I’m not the average person in the RB world and I suspect the average developer with questions may not get their questions answered.  Roth Soft has no support forum so there’s no way to post your questions for others to see and possibly answer (although the ARBP forums has a forum specifically for printing that Roth Soft is pointing to so you might get a question answered there).

Conclusions

RS Report’s strength is that it doesn’t try to do too much for you.  You have to do the placement and that means that your first few reports are going to take a long time.  Afterwards, you can do some very complex reports with minimal effort.  In many ways it’s the  reporting tool that I wish Real Software had inside of REALbasic (with some modifications of course).
RSReport is a wonderful addition to the arsenal of tools for Real Studio.  It is an inexpensive tool that is very powerful and relatively simple to use.  While it’s not perfect  and it’s lacking some features, I think you’ll be pleasantly surprised at how well it works.