So you have visited Report Sculptor website, then finally found some time to download files. And now what ?
As you are probably still confused with all that stuff that you saw on website (and I don't blame you!),
perhaps it is time to finally offer some guidlines and explanations to those of you who might be interested
in all this.
In this blog series I will try to break the ice little bit, and show you that no matter how
complex it all might seem to you at this point (What a heck is on that picture ?!?),
Report Sculptor is actually all about simplicity and pretty much down to earth when it comes
to class of reporting problems it is trying to solve. And as you will later see, it is all very very easy
to understand and get on with it !
This time around I will not get you tired with long pages explaining theory and complex OOP buildup
behind these features, but try to make it more like jumpstart manual, explaining how to get advantage
of this whole thing, in shortest possible time!
Trust me, I did not go through all this, to make things more difficult, quiet opposite :)
You will be versatile in RS reporting before you even know it! (You Already know it! )
But enough talk, let's get down to business :)
We will start first with things that naturally come first;
Download and initial setup
There are two files you have to download in new version 0.90 Beta
(First and second download link respectively);
1) RsDev.Zip
2) RsServer.zip
I will start explaining in reversible order starting with file #2 first, simply because there is really nothing to explain there. This file (RsServer.zip)
is just conveniently packed server deployment, which will be simply dumped (unzipped) somewhere along with your application when
the right time comes. As simple as that; Unzip and dump whole thing right next to your own app. (be that server or client machine)
So let's forget about it all together and proceed with setting up your own RS Reporting - 'Laboratory'
We will take rsDev.zip and unzip it in directly on your ( presumably c:\ ) drive.
So, after you agree to (annoying) WinZip license and finally create C:\RsDev folder with all subfolders underneath, you will open your FoxPro9
and consecutively look for ReportScuptorDemo.pjx located in root folder. When project opens up, go to project tab 'Code' and run myRS.prg.
After that you can run second program marked here, to verify that everything is working. You will get VFP9 preview of HelloWorld prg sample.
Picture 1 Report Sculptor Demo Project
We will take closer look inside myRS.prg later, because there are few important things there regarding later deployment, but we will come back to it
once we actually need it. You don't have RS Report to deliver (at this point) so why bother. Instead I will just say that every time you open this
demo 'RS LAB' you always run this program first, in order to set up development environment. This program essentially calls compiled
ReportSculptor.app which in turn, automatically sets up RS Global Object, initializes GdiPlusX and then sets procedure to itself, so you are set
to run all form samples.
While running demo forms is nice, and you see many nice RS samples, perhaps you don't get to understand much out of it. So we will not go this way.
This is jumpstart crush-course not site-seeing (you probably managed to do that by now already) so instead, we are going straight to the
core of the matter. Develop Report! Believe it or not, by the end of this blog post alone you will be able to develop your very first;
(or first in a long time) ;
Free Report
(Fully OOP at that!)
Before we do that, let's try doing something like a little hypnotherapy, where you try put all troubling thoughts and fears some place else, and
free your mind to learn something only relatively new. Therefore try to erase from your brain all those complex listener constructions
with GDI+ custom rendering, successors, decorators etc. You will much easier understand all this - if you forget all that and have 'clean start' :)
So as clock is ticking. We are sliding back in time.
Now, as your memory takes you couple of decades back in time when (FRX) designers were not even invented yet (let alone listeners) laser jet cost
in a 4000$ range, you can almost hear an awful noise coming from next door... So what was happening there making that much of a noise ?
Account's department is printing payrolls!
But wait minute! All this is happening some 20 years back, they did not have modern report designers back then! So how the heck
they were doing it ?? Well it was hard but obviously not impossible. And more or less everybody did some of that.
Let see now, how do we write one very ordinary report without comfort of having Report Designer at hand.
That is not to keep you permanently in stone age of reporting, but simply to remember basics, which will help you greatly
understand how Report Sculptor Engine works!
Write As You Go / Line By Line
So let now run this little program within your \rsDev\rsDev.pjx 'Report Laboratory'
In order for this to work you have to execute myRS.prg first and set up RS development environment. Then create new prg
and add below code;
******* Open & Relate tables
Close Tables All
use (Addbs(_oRSGO.RS_root) + 'data\categories' ) In 0 Shared order categoryid
use (Addbs(_oRSGO.RS_root) + 'data\products' ) In 0 Shared order categoryid
select products
set relation to categoryid into categories
go top
*set device to printer prompt &&If you want to send it to printer
*set Printer on
****** And then produce raw output on screen using ?/?? commands
?
? ' RS Example of Raw Printing '
? Replicate('-',80)
scan
?
?? Str(Products.categoryid,5,0) at 10
?? Products.productname at 20
?? Transform(Products.unitprice,'$$$,$$$.00') at 60
?
endscan
? Replicate('-',80)
? 'End of report'
*set device to screen
When you run this prg, you shall see raw report lines scrolling on your screen. When I have sent this to
MDI format (via MS Office Document Image Writer) I got 3 pages of raw, character based report.
I amended picture a bit to illustrate flow of lines as if this was to be sent to physical printer. So here it is;
Picture 2 Raw Report
So what do we got here ;
Not much I agree, but enough to understand order of events in physical terms, when this report is to be printed out on matrix or even laser printer
in character mode. Red lines illustrate Page By Page flow of report, while blue lines illustrate Line by Line flow happening within those pages.
Essentially, page is drawn from top to bottom, line by line (only way line printers were able to print them)
up to certain Page Break Point where printer would simply eject it, and start writing new one. This motion would continue until entire report is written.
Paper space below that page break point would be 'Non Printable Area' and would vary from printer to printer.
Note that we did not define any page headers or footers, report groups or anything like that. This is very very basic report level. You can see that
data records are ordered by category and you can see the point where CategoryId (group) changes, but since we did not make any provisions
for this event , then nothing is actually happening except our eye noticing it. Report lines simply flow one after the other as we scan through
'Products' table.
Main reason I took you back to this basic level is that;
If you understood what you have seen above, then you already have in dept understanding of RS Engine.
RS Paging Engine down under, acts pretty much the same way!
You saw that along this code I issued 'set device to printer.' and then redirected output to a printer (MDI you saw) therefore for the sake
of easy understanding Consider it simply a new device.
'Only' difference between your Printer as device, and RS Engine as device is that RS Engine is actually an Object rich in functionalities.
Now since it is an object, instead of doing 'set device to . ' You get to hold object reference of rsEngine object in a variable.
local oRS as rsEngine
oRS=getRsObject(thisform)
oRS.OpenSession()
With oRS
And RSEngine 'device' is now ON
Having done so, I could now continue and recode above shown raw report 1:1, by calling short named RsEngine methods matching
to ?/?? output commands;
.lf()
.lw(25, ' RS Example of Raw Printing ')
.
Endwith
And so for. It would eventually appear almost the same as shown on picture above.
Now there IS big difference between just having printer open with 'set device to printer' and having rsEngine Object instantiated and held as
object reference. RS Engine is fully blown FoxPro object rich with methods and functionalities which give you
Full Power and almost complete control over every aspect of page rendering, and consecutively Report creation. Next to flashing out records
line by line, and flipping pages one after the other, RS Engine is capable of doing many more things!
However, Let's focus on ONE particular feature; RS Engine can render native FoxPro controls on RS Report surface.
Note that idea and method here is NOT to make a snapshot of Form controls (which is doable as well) but to reproduce them
in a practical reporting context. This feature alone brings up entirely new reporting paradigm when it comes to VFP reporting;
Visual OOP Report as VFP9 Form
(In steps 1-2-3 )
Step 1
Create an empty Form, Open & Relate Data via Form.DE
So we add native VFP form to our RS Demo Project. Note that all controls used here will be native VFP controls. This is not some firm requirement
or anything like that; RS can ran from almost any kind of Forms and use your own (framework) controls. I hereby use native controls simply to
demonstrate how RS in fact gives whole new Role to our aging VFP Form Designer & all it's 'dwellers'. As you will later see, Form Designer
becomes not exactly 'Inspector Gadget' , but workable Report Designer at least. Then we open Form Data environment where we Open & Relate Products -> Categories via common categoryId field and index tag
These tables can be found under data folder of RS Demo Project structure and belong to our old friend TasTrade.Dbc
Product table is parent, and it is ordered by index Tag categoryID. Just like we had it in that raw text report earlier.
Picture 3 Open & Relate Data
Step 2
Building Report Sctructure
We add (in this case 3) borderless empty containers painted white, according to reporting structure we want to build.
We also add couple of buttons, one to run it and one to release form while in development mode. That is not really necessary, as all this can
run from invisible form without user interaction. I just added buttons here so we can play with it easier. I also set form back color to little
bit darker gray, for better visibility.
Then we name containers intuitively into 'Detail_Header' , 'Detail' , 'Detail_Footer' respectively
Picture 4 Building Report Structure
Then we reopen Form.DE window and simply start dragging and dropping fields directly on form surface.
Now there is little bit of 'grunt work' involved here. Next to above structuring of report we also have to do resizing, aligning,
setting textbox format/input masks moving objects around etc.
(Bear in mind that this is all built from scratch right here&now, whereas you can have for instance template form having all necessary objects ready
to be filled up. Not to even mention, that since we use real objects we can do much better then just have templates. (Class libraries later)
Picture 5 Grunt Work
When we groomed and aligned our textboxes and labels properly, we distribute them (cut&paste) to respective container bands.
All labels will go to header container and all textboxes will go to detail container preserving alignment all along.
Then finally we put all this together into actual report via code;
Step 3 Stage Data Flow
We will now stage simple Scan/EndScan data flow which will flash form containers we just built as report bands , and then we run
our report (form).
What do I mean by flashing containers as bands ?
Just as ?/?? commands can output some strings and increment some internal line counter, RS Engine have method called
.FlashContainer() which does similar thing, but renders entire containers from our active form to our RS report.
After container and all contained objects are transported to our report surface, RS engine will simply increase current vertical
page position maintained in a property called .nTop (just like VFP increases _plineno ) and writing will continue with next band
(container in this case) .
So report writing principle is again the same as we saw before on raw text example; Write As You Go but with one major difference!
It is no longer Line By Line! Now instead of going line by line, advances are made vertically Band By Band, where 'Band' is actual
(.Flash)Container and it's height in pixels.
And just like in that raw report example; When RS Engine reach some Page Break Point it adds new page and report continues.
Now since RS Engine is fully blown object, this running 'motion' rises various events such are;
Page Footer any time page break point is reached
Page Header any time new page is appended.
There are of course more events happening along, but let's keep it simple for better understanding.
Back to our example;
For simplicity purposes, I will not draw directly Page Headers/Footers but rather let RS Engine render default ones.
(Hence these default PH/PF are customizable, and can be actually your own class objects, so you already get first glimpse of OOP kicking
inn to help productivity.)
So, since RS Engine will handle Headers and Footers, we are left with very simple task / code to write. See right side of the picture, and
watch markings/comments carefully ;
Picture 6 Putting it all together
What you can see on the right side (in green) is something that vaguely resembles FRX detail band with header and footer, but is this
time situated right here in our code to illustrate that you in fact fully control report flow and order of events.
This very simple record loop on products table will be actually driving our report.
As you can see above I added one more label and textbox to footer band to show product count ( as simple reccount() ) and Voila!
Our report is ready!
When you run this form and click run button, you get fully blown report ready to be printed exported etc.
I will expose it via VFP9 native Preview/Print in this case.
Picture 7 Our first OOP Report
RS Engine Behavior
Now let see how did engine behave in this case. As you will see, pretty similar as that raw report flow presented earlier;
Page Break point is followed by Page footer band rather then nonprintable area in this case, but other then that principle is almost the same.
Very simple and intuitive! So have look at picture below to easily understand basic order of events when executing OOP Data Report
with containers as report bands;
Picture 8 Print As Yu Go / Band By Band
However, this order of events is not something carved in stone. Since RS Engine is an object, it is all driven by properties. So here are some of them
that control way page sections are unfolding;
.lAutoFirstPage=.t. && Decides if .OpenSession() method automatically adds first page or you want to do it.
************************************** Page/Report Format and orientation
.rsPageFormat ='A4' &&or 'LETTER','A3' (and the rest to follow soon)
.rsPageOrientation='PORTRAIT' &&Orientation
************************************** Default Page Header Footers
.lAutoPageHeader=.t. && Decides if engine will flash Page Header (or maybe want to do it yourself)
.lAutoPageFooter =.t. && The same as with Page Header
.oPageHeader = oPageHeaderContainerRef && directly 'pin' some container reference as Page Header
.oPageFooter = oPageFooterContainerRef && As for header
****************************************Default Font (true types only)
.rsFontName = "Arial"
.rsFontSize = 8
.rsFnStyleNo = 1 &&Bold, 0 Regular, 2 Italic, 4 Underlined, 128 Strikethrough , and composites
****************************************relative on the fly / default positioning
.pgRemainder && How many pixels remain before page break point is reached.
.nTop && Current Vertical Position on page
.nColumnLeft=25 && Default Left
************************************* ***See sample form #10 for more properties and methods ***
Love being in control ? I thought so ;)
Where does this lead us ?
This was by all means very simple report. It was meant to be this way, so you can understand basic RS Engine motions easily.
As they say; 'You got to learn to walk first before you try flying.' so this example was greatly simplified (or downplayed if you wish)
showcase of power and flexibility this approach gives you, so you can get on your own two feet by understanding very basics.
I understand that by now you are probably bored to death with 'Product By Category' type of report samples, so let see some
real life examples of how you can assert and exercise this power to much greater extend.
Therefore, take look at following report example published in RS Report & Code Gallery.
It is quiet good example of power brought to you by above presented paradigm of code driven report with containers as report bands.
So please have look at it http://www.report-sculptor.com/community/gallerymenu#GroupingOnMultipleInnerBands
Those of you who follow this blog post with an open RS Demo Project in front of you, can open and run form sample #15.
Some of you might say or think 'Big deal, I can do such thing with FRX' .
I am sure you can :) It has been done already many times despite some FRX limitations in this respect, but report itself is not the point here!
What I have presented you in this blog post was actually about something else. If you look inside code there (#15) then that form itself,
you will realize one major difference compared to 'common solutions' to this I would say common reporting requirement
(multiple bands with grouping on each);
If you remember how much of your time and energy you have spent by now on smartly preprocessing cursors, creating dummy indexes and
relations, 'overheating' PrintWhen clauses, adding report variables, UDFs (and what not.) on various reporting problems like this in the
past, You just might like the fact that with RS;
It is no longer you trying to 'trick' predefined FRX paradigm & order of events so you get result report you wish,
It is you who create your own paradigm - So you simply do as you wish.
RS Engine is there to provide services so you can accomplish that task, but you are the one who set the rules to the game :)
Having spelled out this little 'rant' about FRX, I have to clarify once more that RS is not something trying to replace or compete
with FRX/RD. Report Sculptor is designed to compliment FRX based reporting in cases like like those published under gallery/samples;
When FRX have to be 'pushed beyond limits' in order to achieve certain results, or report is impossible to build with FRX/RD.
I wrote RS for this kind of reasons. However, when ordinary report comes which have no any special requirements;
Then I would myself use FRX/RD! I might pass it through RS to get PDF or TIF version, but I would still write it with FRX/RD.
At this point building standard stereotype reports with FRX is still much easier. However do not underestimate (yourself and)
power of OOP concept. Things might change in the future :)
Talking about OOP;
Little game at the end
'Bonus Question'
If you take that simple form we just created together (picture #7 ) and then consecutive result that comes out of it (picture #8)
it might look to you like 'case closed' What else is there to say ? However, let's not overlook few details ( 'Devil lies in details' )
1) It is 100% OOP report in terms of elements used.
2) Despite being very primitive, it is already (90% ) reusable reporting structure
If you take form we just have put together, and clean up all containers bands, leaving them empty and then also remove all
cursor objects object from DE, what do we get ? Your 'bonus question' to win this game is;
Discover 'offending' line of code, preventing you to save this form as Reusable reporting class?
Picture 9 OOP Bonus Question
You guessed it right. It is line #1 :)
select products
If you erase this line and save this form with emptied containers into your own class library,
you just made your first report designer class! Although primitive, you could even use it, to do produce simple record listings .
All you would have to do next time, is add cursors to Form.DE and then drag & drop some fields from there onto form surface
align & groom textboxes/labels and distribute them to those empty band containers. There would be no code required any more.
Very primitive OOP buildup in this case was sufficient to reach 'no code required' situation, and turned this very primitive demonstration form
into simple reporting class.
Ultimate prize on this bonus question you just won - is your own Reporting Freedom. So go out there and cash it :)
And that would be all for now,
In the next blog;
We will further expand on this brand new reporting concept, and show how to do nested report groups, organize totaling etc.
'1-2-3' part of the blog, will be on how to compile and deploy your application with RS reporting enabled.
Stay tuned & Enjoy using Report Sculptor :)