截断的JTable打印输出

我有一个使用JTextArea作为其TableCellRenderer的JTable,因此表格单元格可以使用自动换行。 JTable显示正常。 当我通过JTable的打印方法将表打印到打印机时,输出总是截断大约60%的数据。 我尝试过不同的计算机和不同的打印机,以及不同的打印机驱动程序,不同的JVM版本(1.5,1.6),但这些都没有帮助。 下面是一个自包含的Java主类,可以重现该问题。 有任何想法吗?

import java.awt.*; import java.awt.event.*; import java.awt.print.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; public class JTextAreaJTableTest extends javax.swing.JFrame { public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { JTextAreaJTableTest frame = new JTextAreaJTableTest(); frame.setSize(640, 480); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } JButton jButtonPrint; JScrollPane jScrollPane; JTable jTable; JToolBar jToolBar; public JTextAreaJTableTest() { initComponents(); DefaultTableModel dtm = (DefaultTableModel) jTable.getModel(); Vector<Vector> data = new Vector<Vector>(); for (int i = 0; i < 50; i++) { Vector rowData = new Vector(); rowData.add("Entry " + i); rowData.add("Lorem ipsum dolor sit amet, consectetur adipisicing" + " elit, sed do eiusmod tempor incididunt ut labore et" + " dolore magna aliqua. Ut enim ad minim veniam, quis" + " nostrud exercitation ullamco laboris nisi ut aliquip" + " ex ea commodo consequat. Duis aute irure dolor in" + " reprehenderit in voluptate velit esse cillum dolore" + " eu fugiat nulla pariatur. Excepteur sint occaecat" + " cupidatat non proident, sunt in culpa qui officia" + " deserunt mollit anim id est laborum. " + i); data.add(rowData); } Vector columnNames = new Vector(); columnNames.add("Key"); columnNames.add("Value"); dtm.setDataVector(data, columnNames); jTable.setDefaultRenderer(String.class, null); jTable.getColumnModel().getColumn(0).setCellRenderer( new TextAreaCellRenderer()); jTable.getColumnModel().getColumn(1).setCellRenderer( new TextAreaCellRenderer()); } private void initComponents() { jToolBar = new JToolBar(); jButtonPrint = new JButton(); jScrollPane = new JScrollPane(); jTable = new JTable(); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jToolBar.setRollover(true); jButtonPrint.setText("Print"); jButtonPrint.setFocusable(false); jButtonPrint.setHorizontalTextPosition(SwingConstants.CENTER); jButtonPrint.setVerticalTextPosition(SwingConstants.BOTTOM); jButtonPrint.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jButtonPrintActionPerformed(evt); } }); jToolBar.add(jButtonPrint); getContentPane().add(jToolBar, BorderLayout.NORTH); jScrollPane.setViewportView(jTable); getContentPane().add(jScrollPane, BorderLayout.CENTER); } private void jButtonPrintActionPerformed(ActionEvent evt) { try { jTable.print(); } catch (PrinterException ex) { ex.printStackTrace(); } } public static class TextAreaCellRenderer extends JTextArea implements TableCellRenderer { public TextAreaCellRenderer() { this.setLineWrap(true); this.setWrapStyleWord(true); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.setText(String.valueOf(value)); TableColumnModel columnModel = table.getColumnModel(); this.setSize(columnModel.getColumn(column).getWidth(), 1); int newHeight = this.getPreferredSize().height; if (newHeight > table.getRowHeight(row)) { table.setRowHeight(row, this.getPreferredSize().height); } return this; } } } 

我相信我找到了根本原因和解决方案。 印刷问题源于桌子的高度错误。 该表的高度错误,因为某些表的行高度错误。 有些行是错误的高度,因为它们的单元格渲染器尚未被JTable调用(也就是说,它们的getTableCellRendererComponent方法尚未被调用。)JTable跳过一些单元格渲染器的原因是优化 – 单元格渲染器它跳过用于屏幕外的单元格 – 屏幕外表示不需要渲染; JTable在这方面的优化是有道理的。

但是,渲染器是程序中唯一设置每个行的正确高度的位置。 我在单元格渲染器中设置行高的选择在某种程度上是可以理解的,因为单元格渲染器处于最佳位置以了解该行的高度。

修复此示例程序似乎是最直接的方法是在每个单元格渲染器上手动调用getTableCellRendererComponent (这应该在修改表格的模型数据之后完成。)这使渲染器有机会将表格中的每一行设置为它正确的个人身高。 每行都在正确的高度,JTable总体上最终是正确的高度,这似乎解决了打印截断问题。 以下代码显示访问所有渲染器以执行此操作:

 for (int colIdx = 0; colIdx < jTable.getColumnCount(); colIdx++) { for (int rowIdx = 0; rowIdx < jTable.getRowCount(); rowIdx++) { TableColumnModel columnModel = jTable.getColumnModel(); TableColumn column = columnModel.getColumn(colIdx); TableCellRenderer renderer = column.getCellRenderer(); Object cellValue = jTable.getValueAt(rowIdx, colIdx); renderer.getTableCellRendererComponent(jTable, cellValue, false, false, rowIdx, colIdx); } } 

所有单元格渲染器的手动访问绕过JTable优化仅调用屏幕单元格的单元格渲染器。 因此,您可能只想在用户请求打印之后(但在调用JTable上的print方法之前)执行此变通方法代码。 这样,如果用户只使用GUI而不是打印,JTable优化将保持有效。

我不得不稍微修改Mike Clarks解决方案以使其适用于我:

 for (int colIdx = 0; colIdx < jTable.getColumnCount(); colIdx++) { for (int rowIdx = 0; rowIdx < jTable.getRowCount(); rowIdx++) { TableCellRenderer renderer = jTable.getCellRenderer(rowIdx, colIdx); Object cellValue = jTable.getValueAt(rowIdx, colIdx); renderer.getTableCellRendererComponent(jTable, cellValue, false, false, rowIdx, colIdx); } }