J2TablePrinter is a Java 2 component for printing multi-page JTable documents.  J2TablePrinter converts any JTable or JTable subclass into a Java Pageable, suitable for printing by the J2Printer class (or any Java PrinterJob).  It also implements Flowable for any JTable, so that it may be used with J2FlowPrinter as part of a series of Flowables printed back-to-back.

J2TablePrinter Pagination

J2TablePrinter paginates over multiple pages both horizontally and vertically.  Beginning the J2PrinterWorks 4.0 there are now three different pagination rules supported by J2TablePrinter, which may be specified independently in the horizontal and vertical directions.  The available pagination rules are:

J2PrinterWorks pagination proceeds in "raster" order, i.e., left-to-right across multiple pages horizontally, then top-to-bottom over multiple pages vertically.  When paginating, J2TablePrinter may split large rows and/or columns across page boundaries depending upon how much space remains on the page.  In making this determination, J2TablePrinter first reads the value of getMaximumPaginationGap(), default is 0.2 or 20%.  If the remaining space on the page horizontally is less than getMaximumPaginationGap() percent of the full page width, then the printing of the next column skips to the next page horizontally.  Otherwise, the column is split at the exact pixel boundary that fits the remaining space on the page, with the remainder of the column continuing on the next page horizontally.  Likewise, if the remaining space on the page vertically is less than getMaximumPaginationGap() percent of the full page height, then the printing of the next row skips to the next page vertically.  Otherwise the row is split at the exact pixel boundary that fits the remaining space on the page, with the remainder of the row continuing on the next page vertically.  Thus, in both cases, getMaximumPaginationGap() defines the largest fraction of a page width or height  that it is OK to waste in order to keep columns and/or rows intact.

Column headers can appear on all pages, only the top pages, or not at all. Row headers can appear on all pages, only the left pages, or not at all. The JTable can be left, right, or center justified horizontally, and top, bottom, or center justified vertically. You can also control whether the gridlines and outside lines are printed. J2TablePrinter prints the JTable "WYSIWYG", so that any background colors, fonts, or custom cell renderers will be printed. 



You will find it useful to begin your program with:

    import com.wildcrest.j2printerworks.*;

rather than spell out the full package name for all J2PrinterWorks classes.

J2TablePrinter can instantiated with a zero-argument constructor:

    J2TablePrinter tablePrinter = new J2TablePrinter();

This creates a J2TablePrinter object and initializes all values to their defaults (see the J2TablePrinter Javadoc documentation ).  To specify the JTable to be printed by J2TablePrinter, you can use the J2TablePrinter method setTable:
At this point tablePrinter is a Pageable suitable for printing by J2Printer.

Alternatively, you can use the single-argument J2TablePrinter constructor:

    J2TablePrinter tablePrinter = new J2TablePrinter(yourJTable);

The following is a simple but complete Java program (J2TablePrinterSimplestTest.java ) that displays and prints a JTable using J2TextPrinter:

import java.awt.*;
import javax.swing.*;
import com.wildcrest.j2printerworks.*;

class J2TablePrinterSimplestTest{
    static public void main(String args[]){
        Object[] columns = {"This", "is", "a", "JTable"};
        Object[][] data = {{"table", "", "", ""}, {"", "data", "", ""},
                           {"", "", "goes", ""}, {"", "", "", "here"}};
        JTable table = new JTable(data, columns);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setPreferredSize(new Dimension(400,83));

        JFrame frame = new JFrame("J2TablePrinter test");

        J2Printer printer = new J2Printer();
        J2TablePrinter tablePrinter = new J2TablePrinter(table);


Most of the methods of J2TablePrinter are set and get methods for controlling its property values. The full list of J2TablePrinter methods, what they do, and their default values are given in the J2TablePrinter Javadoc documentation .

General properties

Whether J2TablePrinter is used as a Pageable or a Flowable, you can control the print area (rows and columns) to be printed, gridlines and outside lines, whether it is left, right, or center justified horizontally on a page, top, bottom, or center justified within the remaining space on a page, whether the column heading are replicated on every page, only on the top pages, or not at all

Print area

J2TablePrinter allows you to specify a subarea of contiguous JTable rows and columns to be printed.  The subarea of the JTable may be specified using the J2TablePrinter method:

setPrintArea (int startColumnIndex, int startRowIndex, int numberOfPrintColumns, int numberOfPrintRows)
          Set the print area to be printed.

If either firstColumnIndex or firstRowIndex is less than 0 or past the end of the table, the value 0 will be used instead.  If either numberOfPrintingColumns or numberOfPrintingRows is less than or equal to 0, then the printing area will extend through the rightmost column or bottommost row, respectively.  Likewise, if the values of firstColumnIndex+numberOfPrintingColumns or firstRowIndex+numberOfPrintingRows extend beyond the rightmost column or bottommost row, the printing area will end at the rightmost column or bottommost row, respectively.

The method getPrintArea() returns in a Rectangle object the values of firstColumnIndex, firstRowIndex, numberOfPrintingColumns, and numberOfPrintingRows as the Rectangle's x, y, width, and height values, respectively.  The values returned will be the actual values for the current JTable that result from the most recent setPrintArea call.

The print area feature can easily be adapted to implementing a "print selection" feature common to many client applications since you can query the current selection and set the print area accordingly.  In addition, non-default page breaks can be implemented by using the print area feature to print successive page-sized areas of your own choosing.

Border and gridline control

Since J2TablePrinter performs its imaging using the JTable print and paint methods, you can control the printing of your gridlines using the JTable methods setGridColor(), setShowHorizontalLines(), and setShowVerticalLines().

JTable does not itself include a border, and J2TablePrinter does not print any Border you may have surrounding your JTable.  Instead, as a convenience, J2TablePrinter will optionally print a hairline border around the outside of your JTable with the same appearance (color, etc.) as your JTable gridlines.  This feature may be turned on or off using the J2TablePrinter method:

setOutsideLines (boolean showOutsideLines)
          Indicate whether to add outside lines when printing JTable

Beginning with J2TablePrinter 1.3, the hairline will also be drawn around the JTable column headings if the column heading printing feature is turned on and if setShowOutsideLines is set to true.

Horizontal and vertical alignment

J2TablePrinter will print your JTable either left, center, or right justified horizontally on the page between the left and right margins.  The default value for horizontal alignment is CENTER.

Similarly, J2TablePrinter will print your JTable either top, center, or bottom justified vertically on the page between the gap below the header and gap above the footer.  The default value for vertical alignment is TOP.

setHorizontalAlignment (int horizontalAlignment)
          Sets the horizontal alignment (LEFT, CENTER, RIGHT) for printing the JTable on the page.

setVerticalAlignment (int verticalAlignment)
          Sets the vertical alignment (TOP, CENTER, BOTTOM) for printing the JTable on the page.

Table column headers

The Java JTable component does not automatically display (and therefore J2TablePrinter will not print) table column headers.  The easiest way to get JTable to draw and print with column headers is to enclose it in a JScrollPane, which will cause it to automatically use the TableHeader information to create column headers.  Alternatively, you can add column headers directly using the following code:
    container.setLayout(new BorderLayout());
    container.add(table.getTableHeader(), BorderLayout.NORTH);
    container.add(table, BorderLayout.CENTER);

J2TablePrinter gives you additional control over whether the column headers will be replicated at the top of each new printed JTable page, or just the topmost pages (i.e., preceding row 1 on all horizontally paginated pages), or not at all.   The J2TablePrinter method for controlling this is:

setColumnHeaderPrinting (int columnHeaderPrinting)
          Sets whether column headers printed on ALL_PAGE, TOP_PAGES, or NO_PAGES.

With respect to the header and footer properties such as setLeftHeader that can be specified differently on the FIRST  vs. REST of pages, for a JTable that paginates over multiple pages horizontally, the FIRST settings apply to all the TOP pages and the REST settings apply to the non-TOP pages.

Table row headers

The Java JTable component does not directly support row headers.  However, you can set up row headers for your JTable by putting your JTable in a JScrollPane and calling the JScrollPane method setRowHeader(rowHeaders).  The rowHeaders can be defined using either a JList or a single column JTable.  The J2PrinterWorks sample program J2TablePrinterTestApplication contains code that implements both of these approaches.  The JList approach is simpler but is limited to displaying rows of uniform height.

If row headers are defined for the JTable in this way, J2TablePrinter will print the row headers along with your JTable.   J2TablePrinter lets you control whether the row headers will be replicated at the left of each new printed JTable page, or just the leftmost pages (i.e., preceding column 1 on all vertically paginated pages), or not at all.   The J2TablePrinter method for controlling this is:

setRowHeaderPrinting (int rowHeaderPrinting)
          Sets whether column headers printed on ALL_PAGE, LEFT_PAGES, or NO_PAGES.

Pageable properties

When J2TablePrinter is used as a Pageable, it can have its own ("local") headers & footers (left, center, and right), margins (left, right, top, and bottom), and orientation (portrait & landscape).  Headers and footers can be specified as a String or a JLabel, can be different on the first page vs. the rest of the pages of the Pageable, and can include date, time, and page numbering.  The methods are the same as the parallel set of methods described in the J2Printer section under "Pageable properties".

If "local" values are not specified for this J2TablePrinter instance, the "global" (overall, default) values set using the parallel J2Printer methods will be used.  You can force the J2Printer "global" values to be used by calling the J2TablePrinter method(s) with the argument J2Printer.GLOBAL.

The Pageable properties of J2TablePrinter will be ignored when the J2TablePrinter is used as a Flowable.  This is because in this case the Pageable is the containing J2FlowPrinter, so page properties such as headers, footers, margins, and orientation will be controlled by the J2FlowPrinter Pageable, not the J2TablePrinter used as a Flowable. Note, however, that scaling does work for J2TablePrinter used as either a Pageable or a Flowable, that is, the J2TablePrinter can appear at its own scale within an overall J2FlowPrinter sequence.

Fit-to-page scaling

In addition to regular percentage scaling accomplished using the setScale method, J2TablePrinter also supports fit-to-page scaling when J2TablePrinter is used as a Pageable using the following method:

setMaximumPages (int pagesWide, int pagesHigh)
          Set the maximum number of vertical and/or horizontal pages for printing the J2TablePrinter (will minify to fit).

The setMaximumPages method causes your J2TablePrinter to be scaled down until it fits within pagesWide pages horizontally and pagesHigh pages vertically.  This method cannot be used to magnify and instead will only minify your content (hence the name setMaximumPages).  The method works by starting at a scale of 1.0 and reducing the scale in increments of 0.005 (half a percent) until your J2TablePrinter fits within the prescribed limits.  There is only one scaling factor, which is used both horizontally and vertically, so no distortions are introduced.  If either pagesWide or pagesHigh is set to 0 or less, this is taken as a signal that the scaling in that dimension is unconstrained, that is, the J2TablePrinter can use as many pages as it needs.

The setMaximumPages method causes the rescaling to be calculated and set only at the time it is called and does NOT remember or maintain the page limits you specify, i.e., it is not a state property.  Thus, if you change any printing parameters including your document content, headers, footers, margins, paper size, orientation, etc., you must call setMaximumPages again.

IMPORTANT: If you have been using setMaximumPages(1,0) or setMaximumPages(1,1) to rescale your JTable to one page wide and/or high, you are strongly encouraged to switch to the new SHRINK_TO_FIT pagination mode for the horizontal and/or vertical directions available beginning with J2PrinterWorks 4.0.  SHRINK_TO_FIT mode has the major benefit of being a direct calculation and therefore much faster than the iterative setMaximumPages.  In addition, SHRINK_TO_FIT is a  state that is maintained in the presence of table and/or page size changes and once it is set up it does not need to be reinvoked.  In general, you should use setMaximumPages only if the desired number of horizontal and/or vertical pages is greater than 1.

The percentage and fit-to-page scaling features interact.  You can call setMaximumPages(pagesWide, pagesHigh) to specify a number of pages and then use the method getScale() to find out the resulting scaling factor.  Or you can call setScale(factor) to scale to a desired percentage and then use getNumberOfPages() to find out the number of resulting pages.  The getNumberOfPages() method works for both magnification and minification (thus you could use it to implement your own fit-to-page feature for magnification, which you might call setMinimumPages(pagesWide, pagesHigh)).

Additional features

Variable Row and Column Sizes

J2TablePrinter supports the printing of columns with different widths in JDK 1.2, 1.3, 1.4, or 1.5.  Column widths are specified using the Java API:
J2TablePrinter supports the printing of rows with different heights beginning in JDK 1.3, where this capability has been added as a new JTable feature.  Row heights are specified using the new Java API:
    table.setRowHeight(intRowIndex, desiredHeight);

J2TablePrinter WYSIWYG support

J2TablePrinter inherently performs WYSIWYG printing since it images your JTable instance directly using the Java print and paint methods.  This means you will print all of your JTable's specified fonts, row and column sizes, row and column spacing and alignment, column headings, gridlines, colors, etc.  If you subclass JTable and provide your own custom cell renderers, these also will be displayed and printed.  The general rule is: whatever your JTable can display, J2TablePrinter will print.

You may wish to use the JTable column autosizing feature to expand the width of your JTable columns to fit to the available printing area.  To this end, the J2TablePrinter methods getBodyWidth() and getBodyHeight() are provided to allow you to find out these values given the current printer, margin, header and footer settings.  You can then use the JTable.setSize() method to cause your JTable to resize and fully utilize the available space in accordance with your current autosizing settings.

Non-GUI JTable printing

It is not necessary that the JTable you print be in a JFrame visible on the screen.  You may be printing from a server application and have no display.  Or you may have a JTable displayed but wish to print from a different non-GUI copy of the JTable.  The latter situation can arise when you want to set the printing JTable properties different from your on-screen JTable display, such as to force white backgrounds, different column widths, or different fonts as appropriate for a printed page.  In such cases, you can use code like:

  JTable table2 = new JTable();
  table2.setSize(table2.getPreferredSize()); // size required

Note that this simple example does not result in JTable column headings.  The easiest way to make column headings appear is to enclose your JTable in a JScrollPane as shown in the J2TablePrinterSimpleTest application code above.  Even if you do use a JFrame, you  can still specify JFrame.setVisible(false) so it does not appear on the screen, or alternatively JFrame.setLocation(10000,10000) to move it off-screen.

Using J2TablePrinter as a JavaBean

The J2PrinterWorks components are designed to work as a JavaBeans components in visual builder environments.  However, J2PrinterWorks uses APIs unique to the Java 2 system, and not all visual development environments currently work and build visually with Java 2-based components.  In particular, WebGain/Symantec Visual Cafe has to be specially configured to allow you to import the J2PrinterWorks components into its component library and exhibits other problems when using it visually. In contrast, Borland JBuilder and IBM VisualAge for Java can read and use J2PrinterWorks.jar as either a set of JavaBeans components or programmatically as classes.  See Installation & Compatibility for further details.  Since the J2PrinterWorks components are not GUI components per se, the need to work with them visually isn't great, so that using them programmatically isn't much of a limitation.

If J2PrinterWorks.jar is properly installed, you will see the J2PrinterWorks components, including J2Printer and J2TablePrinter, in the component palette of your visual programming environment.  Click on the J2Printer bean and drop it on your work area and likewise drag the J2TablePrinter bean and drop it on your work area.  You will see icons representing instances of these beans.  These will not be displayed at run-time.

When you bring up the property sheet for either component, you will be able to see and edit their properties.  The properties may be set as desired, with values as defined in the Javadoc documentation .

You can make the J2Printer bean print by using your visual programming environment to perform event wiring from an actionPerformed event such as a button push to the J2Printer "print" event target method.  You can use this to print the instance of J2TablePrinter, using the setTable method or the J2TablePrinter constructor itself to specify your JTable.

All the J2PrinterWorks properties are bound properties.  You may use your visual programming environment to do property-to-property binding in either direction between the J2PrinterWorks components and your other beans.  None of the J2PrinterWorks properties are constrained properties.  This frees you from having to place try...catch blocks around your "set" calls in regular programming.

J2PrinterWorks components are fully serializable.  After customizing any properties, instances can be saved along with any other beans to which they may be wired.  When reloaded, the instances will come back with their customized values.  No J2PrinterWorks properties are declared transient.

Copyright 2009, Wildcrest Associates (http://www.wildcrest.com )