Printing JTComponents and JTable

totsubo
totsubo used Ask the Experts™
on
Here are the specs:

1- Print out the contents of a JTable which may span multiple pages
2- At the top of the first page print out a JPanel

This should be easy but I'm just not understanding how to use translate() and clip().

Here's the code I have so far, but it isn't printing things properly at all ...

package TAL.TALObjects;

import TAL.Panels.*;
import java.awt.print.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class Preview extends javax.swing.JFrame implements Printable {
 
  private JTable table;
  private CustomerReceiptTopPanel topPanel;
  private int tableWidth = 0;
 
  public Preview(JTable table, CustomerReceiptTopPanel topPanel) {
    this.table    = table;
    this.topPanel = topPanel;
    setColumnWidths(table); //makes the tablecolumns as wide as needed
    initComponents();

    getContentPane().add(topPanel, new java.awt.GridBagConstraints());

    scrollPane.setViewportView(table);
    pack();
    setSize(tableWidth + 100, 800);
    setVisible(true);
  }
 
  public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
   
    Graphics2D g2 = (Graphics2D) g;
    double scale = 1;
    double topPanelYClip = 0;
    g2.setColor(Color.black);
   
    //how much room will the Header of the first page take?
    double topPanelHeight = topPanel.getHeight();

    //calculate the scaling factor (if needed)
    double pageHeight = pf.getImageableHeight();
    double pageWidth  = pf.getImageableWidth();
    double tableWidth = (double)table.getColumnModel().getTotalColumnWidth();
    if (tableWidth >= pageWidth) { scale =  pageWidth / tableWidth; }

    double headerHeightOnPage = table.getTableHeader().getHeight() * scale;
    double tableWidthOnPage   = tableWidth * scale;
   
    double oneRowHeight = (table.getRowHeight() + table.getRowMargin()) * scale;
    int numRowsOnAPage   = (int)((pageHeight - headerHeightOnPage) / oneRowHeight);
    double pageHeightForTable = oneRowHeight * numRowsOnAPage;

    int numRowsTakenByTopPanel = (int)Math.ceil(topPanelHeight / oneRowHeight);
    int numRowsOnFirstPage     = numRowsOnAPage - numRowsTakenByTopPanel;
    double pageHeightForTableOnFirstPage = oneRowHeight * numRowsOnFirstPage;
   
    int totalNumPages = (int)Math.ceil(((double)table.getRowCount() - numRowsOnFirstPage) / numRowsOnAPage) + 1;
    if(pageIndex >= totalNumPages) { return NO_SUCH_PAGE; }

    //move the pen to 0,0 of the page (takes into account margins)
    g2.translate(pf.getImageableX(), pf.getImageableY());

    //move the pen down below the header
    g2.translate(0f,headerHeightOnPage);
    //move the pen all the way back to 0,0
    if (pageIndex == 0) {}
    else g2.translate(0f,-(pageIndex - 1) * pageHeightForTable - pageHeightForTableOnFirstPage);
       
    if (pageIndex == 0) {
      //set clip for printing only the top panel
      g2.setClip(0,0, (int)topPanelHeight, (int)tableWidthOnPage);
      topPanel.print(g2);
    }
   
    //If this piece of the table is smaller than the size available,
    //clip to the appropriate bounds.
    if (pageIndex + 1 == totalNumPages) {
      int lastRowPrinted = numRowsOnAPage * pageIndex - numRowsTakenByTopPanel;
      int numRowsLeft = table.getRowCount() - lastRowPrinted;
      g2.setClip(0,
      (int)(pageHeightForTable * pageIndex + topPanelHeight),
      (int) Math.ceil(tableWidthOnPage),
      (int) Math.ceil(oneRowHeight * numRowsLeft));
    }
    //else clip to the entire area available.Unless this is the first page ...
    else{
      if (pageIndex == 0) {
        g2.setClip(0,
        (int)(topPanelHeight),
        (int) Math.ceil(tableWidthOnPage),
        (int) Math.ceil(pageHeightForTableOnFirstPage));
      }
      else {
        g2.setClip(0,
        (int)(pageHeightForTable * pageIndex),
        (int) Math.ceil(tableWidthOnPage),
        (int) Math.ceil(pageHeightForTable));
      }
    }
   
    g2.scale(scale,scale);
    table.print(g2);
    g2.scale(1/scale,1/scale);
    g2.translate(0f,pageIndex*pageHeightForTable);
    g2.translate(0f, -headerHeightOnPage);
    g2.setClip(0, 0,
    (int) Math.ceil(tableWidthOnPage),
    (int)Math.ceil(headerHeightOnPage));
    g2.scale(scale,scale);
    table.getTableHeader().print(g2);
    //paint header at top
   
    return Printable.PAGE_EXISTS;
  }
 
  private void initComponents() {

    scrollPane = new javax.swing.JScrollPane();

    getContentPane().setLayout(new java.awt.GridBagLayout());
  }
}
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
I've read it already. I obviously didn't quite get it though :)

Can you help with fixing my code?

Author

Commented:
I've fixed my code and now it *almost* works. The problems I have now are:

1- sometimes at the bottom or top of a page I get partial printing of a table row. How can I make sure that I don't print partial rows at the bottom of a page? (And conversely that printing at the top of the page starts with a full row)

2- I need to print two copies of the same thing on each page. i.e. this format

---
|A|
---
|A|
---

How can I use the code I have now that prints one copy per page and adapt it so that I print two copies per page.

Thanks!

The new code:

  public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
   
    Graphics2D g2 = (Graphics2D) g;
    double scale = 1;
    double topPanelYClip = 0;
    g2.setColor(Color.black);
   
    //how much room will the Header of the first page take?
    double topPanelHeight = topPanel.getHeight();

    //calculate the scaling factor (if needed)
    double pageHeight = pf.getImageableHeight();
    double pageWidth  = pf.getImageableWidth();
    double tableWidth = (double)table.getColumnModel().getTotalColumnWidth();
    if (tableWidth >= pageWidth) { scale =  pageWidth / tableWidth; }

    double headerHeightOnPage = table.getTableHeader().getHeight() * scale;
    double tableWidthOnPage   = tableWidth * scale;
   
    double oneRowHeight = (table.getRowHeight() + table.getRowMargin()) * scale;
    int numRowsOnAPage   = (int)Math.floor((pageHeight - headerHeightOnPage) / oneRowHeight);
    double pageHeightForTable = oneRowHeight * numRowsOnAPage;

    int numRowsTakenByTopPanel = (int)Math.ceil(topPanelHeight / oneRowHeight);
    int numRowsOnFirstPage     = numRowsOnAPage - numRowsTakenByTopPanel;
    double pageHeightForTableOnFirstPage = oneRowHeight * numRowsOnFirstPage;
   
    int totalNumPages = (int)Math.ceil(((double)table.getRowCount() - numRowsOnFirstPage) / numRowsOnAPage) + 1;
    if(pageIndex >= totalNumPages) { return NO_SUCH_PAGE; }

    //move the pen to 0,0 of the page (takes into account margins)
    g2.translate(pf.getImageableX(), pf.getImageableY());

    if (pageIndex == 0) {
      topPanel.print(g2);
      //put pen below the top panel
      g2.translate(0f,  topPanelHeight);
      g2.scale(scale,scale);
      table.getTableHeader().print(g2);
      g2.scale(1/scale, 1/scale);
      g2.translate(0f,  headerHeightOnPage);
      g2.setClip(0, 0, (int)Math.ceil(tableWidthOnPage), (int)Math.ceil(pageHeightForTableOnFirstPage));
      g2.scale(scale,scale);
      table.print(g2);
      g2.scale(1/scale, 1/scale);
    }
    else {
      g2.scale(scale,scale);
      table.getTableHeader().print(g2);
      g2.scale(1/scale, 1/scale);
      //needed to place pen below table header
      g2.translate(0f,  headerHeightOnPage);
      g2.translate(0f,  -(pageHeightForTable * (pageIndex-1) + pageHeightForTableOnFirstPage));
      g2.setClip(0, (int)Math.ceil(pageHeightForTable * (pageIndex-1) + pageHeightForTableOnFirstPage), (int)Math.ceil(tableWidthOnPage), (int)Math.ceil(pageHeightForTable));
      g2.scale(scale,scale);
      table.print(g2);
      g2.scale(1/scale, 1/scale);
    }

    return Printable.PAGE_EXISTS;
  }
Become a CompTIA Certified Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Author

Commented:
fixed problem #1 by changing:

oneRowHeight = (table.getRowHeight() + table.getRowMargin()) * scale;

to

oneRowHeight = table.getRowHeight() * scale;

Can anyone help with #2?

Jc

Author

Commented:
Asking for this question to be deleted since I have not received an answer yet.
A request for a refund has been made.  Experts, you have 72 hours to object.

SpideyMod
Community Support Moderator @Experts Exchange
PAQ'd and all 300 points refunded.

SpideyMod
Community Support Moderator @Experts Exchange

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial