B4J Library B4j Report Writer

This is a Class and 4 custom views that implements a basic reportwriter for B4j. I have developed this for an app I am working on, I've tried to make it generic enough to be of use to others but it is certainly not fully tested for all possibilities as they could be varied.

The 4 custom views are:


You can create a columnar report that implements a subtotal and total row, or totally freeform report using just static fields, or a mixture of both.

The required layout (See the layout ReportWriterTemplate in the demo app) has 3 required panes:

pnHeader, pnContent and pnFooter. Any of these can be empty or invisible, but they must be there.

pnHeader and pnFooter are self explanatory, they can contain any number of Static fields pnContent is explained below.


How it works

A report layout is defined using the B4j designer. It's name is passed to the initialize method of the reportwriter, along with an initial size for the report. The final size is determined by selection of a printer using the print dialog.

For StaticFields, you assign a name to each field in the designer and then in your program add the data to a map with a key of the same name. The data is then displayed in the field at runtime.

For the columnar part of a report, you do not assign names to the fields, they are populated from a list of arrays added to the data map with a key of "RowData" that contains rows of data in the order in which it is to be displayed. It sounds complicated, but have a look at the ColumnReport in the example, it's really fairly straightforward.


pnColumnHeader should only contain ColumnHeaderFields. It's text is displayed in the ColumnHeaderRow. The column header field also allows you to assign a format string that is applied to all of the fields in that column. The format string is used to feed options to the NumberFormat2 function and takes the form

See Numberformat2 for clarification, the trailing comma turns on Grouping.

pnRow should only contain Columnfields, you can add an identifier for a subtotal and total which must match an Identifier in a TotalField in pnSubTotal and/or pnTotal whichever is required.

pnSubTotal and pnTotal can contain labels and Totalfields. The labels are only used to display text, the total fields will display a subtotal or grandtotal depending on which pane they are in. TotalFields have their own FormatString that can be entered in the designer.

You can also add one or more styleclasses to the custom views for formatting with CSS. Each pane also has it's own styleclass (see the code for reference).


You can put staticfields pretty much anywhere else in a report (see the InformationPage example), they should be contained in panes which have a unique id in a tag, these should then be registered with the reportwriter so that the fields can be added to the field map and matched to the data map when you pass data to it. You can enter a FormatString for Static fields, this will cause an error if you enter a formatstring and the data passed to the field is not a number.

There are 3 examples in the attached project (RW.Zip), ColumnReport (mainly uses columns, subtotals and totals), InformationPage (uses StaticFields) and Invoice (a mixture of the two).

This is just a quick overview, see the comments in the code and post any questions and I'll do my best to answer them.

Known Issues:
For some reason, a border is still printed if a fields borderwidth is set to 0, so you also need to set the border color to match the background color (or make it transparent) to stop it being seen.

Matching output to a printed page size can be tricky, you may need to experiment with variant sizes in the designer to get it to look exactly how you want it. The reportwriter does provide the ability to scale a page to fit the available printer page size (and optionally keep the aspect ratio) which may help, or it may not.

The demo app depends on the javafx8 print library

This should be considered an alpha release, please test it thoroughly before use in a production app.

There is currently very little data validation, you need to make sure that the number of columns passed to the reportwriter is the same as defined in the layout. Let's see what other problems are found which will depend largely on how you try to use it and we may be able to make it a bit more resilient.

I hope you find it useful.

Updated to V0.6 to work in Obsfuscated mode.
Updated to V0.7 with a ReportWriterPreview class, provides a better preview. See post #4 Depends on jNumberSpinner Lib.

upload_2016-2-29_1-43-30.png upload_2016-2-29_1-49-6.png upload_2016-2-29_1-50-16.png


  • RW0.7.zip
    34.5 KB · Views: 776
Last edited:


Licensed User
Longtime User
If it should be a string, you need to remove the Format string from the corresponding columnHeaderField in the designer


Active Member
Licensed User
Longtime User
Java page 3 does not eliminate the header or footer of page 2 and 3.
I had to force the non-printing of the column titles for page 2 and 3.

My app checks the source table every 30 seconds to see what has NOT been printed.
It will retrieve 1 row (regardless of how many), print it, and wait (x) 30 seconds to check again.
This was required cause many new printed reports would produce corruption in printed results (???).

Since there is only 1 Rowdata, everything needs to be added to the report in Rowdata, including col-headers.

Excellent for producing a single - simple page, but me thinks we could expand it to a "banded" report generator.
ie. - Many col headers, and data rows in a report.

Things we can now do...
Can traverse source table(s) data and create a temp table, creating a normalized row that doesn't need much processing to print, using a language we know and understand.
RW doesn't need heavy formatter's to print results - rows and cols are already formatted.
Can make the engine "light".

Professional Report Writers have gone overboard trying to meet everyone's needs. I don't think we need this here.
Please help me understand how we can achieve a simple banded report writer.


"Professional Report Writers have gone overboard trying to meet everyone's needs. I don't think we need this here.
Please help me understand how we can achieve a simple banded report writer."

Truer words...

The Windows/Mac/HTML GUI world is full of welcome advancements. But we've also abandoned human-desktop conveniences, without a debate.

The menus in old Lotus Spreadsheets, as well as Report Writers like R&R and Bandit/Triplevision, were triggered by a single slash / key, and then each menu function was triggered by a single letter. It wasn't the same feel as hot keys like Ctrl-S to Save ; there was more of a feeling of being in control.

It was possible to become so fast at Saving and Loading Reports, that you could no longer explain it in words to another users. The memory was in the fingers, so you would have to use your fingers to remember all of the steps.

I'd give anything, to have a modern banded report writer that was primarily keyboard-driven.


Licensed User
Longtime User
The code is there, feel free to improve or amend it as you wish, just post your improvements so the community can benefit.