Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8210807

Printing a JTable with a JScrollPane prints table without rows populated

XMLWordPrintable

    • 9
    • b24
    • x86_64
    • windows_10

      ADDITIONAL SYSTEM INFORMATION :
      Reproduced on Windows 10 using Java 11. The table prints fine with the JScrollPane with Java 1.8.0_181

      A DESCRIPTION OF THE PROBLEM :
      A simple JTable doesn't print correctly if the table is contained in a JScrollPane. The same table prints correctly if it's added directly to a JPanel without a JScrollPane.

      Side note: Setting up the JScrollPane to always hide the scroll bars doesn't change the result.

      REGRESSION : Last worked in version 8u181

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      - Run source code below.
      - Print to "Microsoft Print to PDF" printer
      - Open saved pdf
      - Notice printed table doesn't match table visible in program window


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Table printed in pdf should have same number of rows as table appearing in program window
      ACTUAL -
      Table printed in pdf has a complete header but has no row data.

      ---------- BEGIN SOURCE ----------
      import java.awt.*;
      import java.awt.print.*;
      import java.awt.event.WindowEvent;
      import javax.swing.*;
      import javax.swing.table.DefaultTableModel;

      public class TablePrintTest extends JFrame {

      public static void main(String[] args) {
      new TablePrintTest();
      }
      public TablePrintTest() {

      // Create table with a JScrollPane
      TestTable testTable = new TestTable(true); // Table row contents don't print

      // Create table without JScrollPane
      //TestTable testTable = new TestTable(false); // Table prints correctly

      add(testTable);
      pack();
      setVisible(true);
      PrintUtilities printerJob = new PrintUtilities(testTable);
      printerJob.print("Test Table Print");
      }

      public class TestTable extends JPanel {

      public TestTable(Boolean useScrollPane) {

      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

      DefaultTableModel model = new DefaultTableModel();
      model.addColumn("Column 1");
      model.addColumn("Column 2");
      model.addColumn("Column 3");
      model.addColumn("Column 4");

      for (int row=1;row<=5;row++)
      model.addRow(new Object[] {
      "R"+row+" C1", "R"+row+" C2", "R"+row+" C3", "R"+row+" C4" });

      JTable table = new JTable(model);

      if (useScrollPane == true) {
      JScrollPane sp = new JScrollPane(table,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      sp.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
      add(sp);
      } else {
      add(table.getTableHeader());
      add(table);
      }
      }
      }

      /** A simple utility class that lets you very simply print
      * an arbitrary component. Just pass the component to the
      * PrintUtilities.printComponent. The component you want to
      * print doesn't need a print method and doesn't have to
      * implement any interface or do anything special at all.
      * <P>
      * If you are going to be printing many times, it is marginally more
      * efficient to first do the following:
      * <PRE>
      * PrintUtilities printHelper = new PrintUtilities(theComponent);
      * </PRE>
      * then later do printHelper.print(). But this is a very tiny
      * difference, so in most cases just do the simpler
      * PrintUtilities.printComponent(componentToBePrinted).
      *
      * 7/99 Marty Hall, http://www.apl.jhu.edu/~hall/java/
      * May be freely used or adapted.
      */

      class PrintUtilities implements Printable {
      private Component componentToBePrinted;

      public void printComponent(Component c, String jobname) {
      new PrintUtilities(c).print(jobname);
      }

      public PrintUtilities(Component componentToBePrinted) {
      this.componentToBePrinted = componentToBePrinted;
      }

      public void print(String jobname) {
      PrinterJob printJob = PrinterJob.getPrinterJob();
      PageFormat pf = printJob.defaultPage();
      pf.setOrientation(PageFormat.PORTRAIT);

      // set margins to 1/2"
      Paper p = new Paper();
      p.setImageableArea(36, 36, p.getWidth()-72, p.getHeight()-72);
      pf.setPaper(p);

      printJob.setPrintable(this, pf);
      printJob.setJobName(jobname);

      if (printJob.printDialog()) {
      try {
      printJob.print();
      } catch(PrinterException pe) {
      System.out.println("Error printing: " + pe);
      }
      //componentToBePrinted.setMaximumSize(new SimDimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
      }
      }

      public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
      if (pageIndex > 0) {
      return(NO_SUCH_PAGE);
      } else {
      Graphics2D g2d = (Graphics2D)g;
      g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
      Component c= componentToBePrinted;

      double panelX= c.getWidth();
      double panelY= c.getHeight();
      float imageableX = (float) pageFormat.getImageableWidth()-1;
      float imageableY = (float) pageFormat.getImageableHeight()-1;

      // JPR - Try to do a distortion free scale by scaling both dimensions by the same
      // amount, based on the dimension that needs to be scaled the most
      // orig code - g2d.scale(imageableX/panelX,imageableY/panelY);

      double xscale = imageableX/panelX;
      double yscale = imageableY/panelY;
      double optimalScale;
      if (xscale < yscale)
      optimalScale = xscale;
      else
      optimalScale = yscale;

      if (optimalScale > 1)
      optimalScale = 1; // Don't make the image bigger

      g2d.scale(optimalScale, optimalScale);
      disableDoubleBuffering(c);
      c.paint(g2d);
      enableDoubleBuffering(c);
      return(PAGE_EXISTS);
      }
      }

      /** The speed and quality of printing suffers dramatically if
      * any of the containers have double buffering turned on.
      * So this turns if off globally.
      * @see enableDoubleBuffering
      */
      public void disableDoubleBuffering(Component c) {
      RepaintManager currentManager = RepaintManager.currentManager(c);
      currentManager.setDoubleBufferingEnabled(false);
      }

      /** Re-enables double buffering globally. */

      public void enableDoubleBuffering(Component c) {
      RepaintManager currentManager = RepaintManager.currentManager(c);
      currentManager.setDoubleBufferingEnabled(true);
      }
      }

      protected void processWindowEvent(WindowEvent e) {
      if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
      }
      }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Don't put the table in a JScrollPane. Instead add the table header and table manually to the parent JPanel and print that.

      FREQUENCY : always


            tr Tejesh R
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: