57 45 4c 4c 20 44 4f 4e 45 21
                   
Sep 18

Printing SWT Tables with PaperClips

Posted on Friday, September 18, 2009 in Articles, Eclipse Articles.

In this article I will explain how to print a table using PaperClips (as of this writing PaperClips is in process of moving to the Eclipse Nebula project). When I say print, I mean print literally, as in printing on a printer. PaperClips is a lightweight API that makes building printable pages very easy. It uses a simple and logical structure that has many useful features and it’s surprisingly flexible. One of the many possibilities is the ability to print tables quite nicely as it has a “GridPrinter” (which is what this article will cover. But you can of course use PaperClips to print nearly anything).

The code for this article will let you print pretty much any SWT table widget of your choice as all you need to do is wrap your table in an interface and off you go. But since this is an article, let’s stick to the plain old SWT table for the sake of the demo. I will mostly go over important snippets of the code and the rest you can download and re-use (download link is at the bottom of the article).

Let’s list a few things we want to achieve with our implementation:

  • Print preview (PaperClips gives us most of this already).
  • The option to print either just a selection or all items.
  • Customizable header and footer.
  • Printing table with column sizes as they are in the table.
  • Options to specify if headers are printed, where lines are drawn and so on.

The table that we intend to print for this article looks like this (just run the Tester.java class in Eclipse):

Table Screenshot

We use Snippet38 and add a button at the bottom for printing.

Understanding Paperclips

It’s probably ideal that you understand the PaperClips syntax before you keep reading. PaperClips has certain letters and things that let you specify column widths, how things span and wrap etc. Please do a quick scan of this page if you are unfamiliar with the syntax. It will take no more than a few minutes to learn, it’s that easy.

Creating a GridPrint

As mentioned, the GridPrint class is basically a class for printing grids. It will allow you to set things such as columns, headers etc. Think of it as a table widget, but as if it was drawn on a piece of paper.

Our main class that will handle all the printing will be called GridPrinter.java, and the constructor looks like this:

public PrintResultCode printTable(IGenericTable tableImpl, boolean printSelectionOnly, boolean showPreview, String docTitle, final Shell parentShell) {
 ...
}

The IGenericTable is an interface that you use to wrap the SWT table you want to print. It contains simple methods such as getting the name or width of a column, or an item on a specific row (methods that most table implementations already have). The second attribute defines whether everything is printed or only what the user has selected is printed. The third defines if we show a Print Preview dialog or just print straight to the printer. The fourth is the title of our document that we are printing and finally it’s the shell that will be the parent shell of the print preview dialog (if we are previewing).

Now that we have all the “data” we need, the first thing we want to do is to create the column headers. This is done via a very short loop;

for (int i = 0; i < cols.size(); i++) {
    String name = concat(tableImpl.getColumnTitle(cols.get(i)), widths.get(i), concatGc, headerFont);
    print.addHeader(new TextPrint(name, _headerFontData));
}

We get the table column text and then concatenate it if it’s longer than the actual width of the column itself (just like the table does as a widget). print is our GridPrint, and to that we simply say “add this header”, and then create a TextPrint with the name and our specified header font. A TextPrint can be thought of as a basic cell that contains text with or without a font. Do note that pretty much everything is a “print”, so you can add a GridPrint to a GridPrint to a GridPrint etc. You get the idea.

Now that we have our table column header added, let’s add the cell data that goes below.

for (IDataObject gi : sel) {
    for (int i = 0; i < cols.size(); i++) {
        String colText = gi.getColumnText(cols.get(i));
        if (colText == null) {
            colText = "";
        }
        String text = concat(colText, widths.get(i), concatGc, cellFont);
        print.add(tp(text, _cellFontData));
    }
}

It’s nearly identical but instead of adding it as a header to the GridPrint we just add it normally. We do the same concatenation as in the header as we want to print exactly what the table looks like (so if the user resizes a column in the table widget, that’s the size that is used for the printed version as well). The sel array represents all selected items. If we called our constructor with the option to print all items, it will contain all items, and if we called it and said “only print the selected items”, it will contain those. The code also contains logic for spacing out cells, so if you were to select individual cells like this…

# - - # - -
- # # - - -
- - - - - #

… it would print it in the way you would expect it to.

Multiple Pages and Large Prints

As the code is not a human and has no idea of how big your table actually is, it’s quite possible it spans multiple pages both horizontally or vertically. A GridPrint does not handle this by default. But remember that pretty much all print-classes can be children of each other? To support large prints (basically anything beyond the size of a single printed sheet of paper), we need to wrap our page (the GridPrint) in a BigPrint. Just by doing that via a simple…

BigPrint big = new BigPrint(print);

… we can now support multiple pages. Easy wasn’t it?

Headers, Footers and Spacing

Normally you will want headers and footers on the printed paper. The header tends to contain your company logo and the document title. The footer usually contains what page it is and perhaps a date or such. To accommodate this, there is a PagePrint class that will let you customize all of these aspects. To use it we want that to be our “outermost” parent, so the order is: PagePrint -> BigPrint -> GridPrint.

Here’s how we create the PagePrint:

PagePrint pp = new PagePrint(new PrintHeader(_printHandler, docTitle), big, new PrintFooter(getFooterText()));
pp.setHeaderGap(9);
pp.setFooterGap(18);

In the constructor, we tell it “here’s our header, our BigPrint and our footer”. We also tell it how much spacing we want between the header/footer and the content of the page. It’s usually nice to space them out slightly so it’s not too packed together.

The header and footer classes are both classes that implement the PaperClips PageDecoration interface. They’re very simple to use and only require one method. All this method forces you to return is a “Print” that represents your header (or footer). They can be of any print-class you like, a GridPrint, a TextPrint, etc. For example, here’s our header:

@Override
public Print createPrint(PageNumber arg0) {
    DefaultGridLook dgl = new DefaultGridLook(0, 3);
    GridPrint gp = new GridPrint("p, C:D:GROW", dgl);
    FontData fd = Display.getDefault().getSystemFont().getFontData()[0];
    fd.height = 14;
    fd.setStyle(SWT.BOLD);

    if (_handler.getActivePrintLogo() != null) {
        gp.add(new ImagePrint(_handler.getActivePrintLogo().getImageData(), Display.getDefault().getDPI()));
        gp.add(new TextPrint(""));
        gp.add(SWT.CENTER, new TextPrint(_title, fd, SWT.CENTER), GridPrint.REMAINDER);
    }

    return gp;
}

In this code we create a new “Grid Look and Feel” (this is a PaperClips class that simply draws borders around cells etc). Then we create a very simple GridPrint that has 2 columns. The first is in a preferred size as we don’t know the size of the image that will go there (there might be no image even). The second takes up all available space and is centered so that the text shows the title of the document in the middle, but we push it down a row to make it truly centered or the size of the image would push it off.

Previewing the Print

Once we have our PagePrint all set up it’s finally time to print! PaperClips has a “ui” package that contains a PrintPreview dialog. In the downloadable code you will find that this class has been wrapped as I wanted button images in the dialog to be customizable. To show our print preview dialog we call:

PrintPreviewDialog ppd = new PrintPreviewDialog(pp, parentShell, _printHandler);
ppd.open();

(The PrintHandler is an interface that lets us define what images we use etc)

The result is more or less the following (when fully zoomed out):

Zoomed Out Picture

And when zoomed in a bit:

Zoomed In Picture

Do note that even if the preview may not be 100% perfect look-wise (pixelated etc), the printed version will come out fine.

Conclusions

With PaperClips you can go from zero print-functionality in your application to some pretty fancy reports in just a few hours of work. That’s its #1 strength and it’s a very strong argument for using PaperClips. Sure, you can create very fancy reports using Eclipse BIRT or JasperReports (which has sadly gone mostly commercial). For “normal printing” however, there’s no reason to dig into a big reporting engine, just stick to PaperClips!

Download The Code

The code for this article is an Eclipse Project that contains everything necessary to run what you have seen in this Article (you may need to adjust the SWT-jar import paths). It may seem like there’s a lot of code but in reality it’s mostly some extra interfaces to make things customizable. That way it’s not just article code, but code you can actually use. That’s how I prefer to write articles. Most people want as much customization as possible, and for those that don’t, they can take out the parts that they need.

Download Code

Happy printing!

(PaperClips version 1.0.4 was used in this article).

  1. Glazed Lists + SWT Tables == True If you haven’t heard about Glazed Lists until now, it’s...
  2. MenuManagers and You If you’re using Eclipse RCP (or even standalone SWT with...
  3. XAML in SWT / Where The Ribbon Is I get loads of traffic and email thanks the Ribbon....

1 Response to “Printing SWT Tables with PaperClips”

  1. Matthew Hall - November 13th, 2009

    In your page header: consider using new EmptyPrint() instead of new TextPrint(“”) for empty grid cells.