2011-02-04 13 views
5

Tengo una JTable que usa JTextArea como TableCellRenderer, de modo que las celdas de la tabla pueden utilizar el ajuste de palabras. JTable muestra bien. Cuando imprimo la tabla en una impresora a través de JTable's print method, la salida siempre se trunca aproximadamente al 60% de los datos. He probado diferentes computadoras y diferentes impresoras, y diferentes controladores de impresora, diferentes versiones de JVM (1.5, 1.6) pero nada de eso me ha ayudado. A continuación se muestra una clase principal independiente de Java que reproduce el problema. ¿Algunas ideas?Salida de impresión JTable truncada

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<String>> data = new Vector<Vector<String>>(); 
     for (int i = 0; i < 50; i++) { 
      Vector<String> rowData = new Vector<String>(); 
      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<String> columnNames = new Vector<String>(); 
     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; 
     } 
    } 
} 

Respuesta

0

Creo que encontré la causa y una solución. El problema de impresión se debe al hecho de que la mesa tiene una altura incorrecta. La tabla tiene una altura incorrecta porque algunas de las filas de la tabla tienen la altura incorrecta. Algunas de las filas tienen una altura incorrecta porque JTable no ha invocado sus representadores de celda (es decir, no se ha llamado al método getTableCellRendererComponent). La razón por la que JTable omite algunos de los representadores de celda es la optimización: la celda representa los omisiones. son para celdas que están fuera de la pantalla; fuera de pantalla significa que no se necesita renderizar; La optimización de JTable en esta área tiene sentido.

Sin embargo, los procesadores son el único lugar en el programa donde se establece la altura correcta de cada fila individual. Mi elección para establecer la altura de la fila en el renderizador de la celda es algo comprensible porque el renderizador de la celda está en la mejor posición para saber qué altura debe tener la fila.

Parece que la forma más sencilla de arreglar este programa de ejemplo es llamar manualmente al getTableCellRendererComponent en cada procesador de celda (esto debe hacerse después de modificar los datos del modelo de la tabla). Esto les da a los procesadores la oportunidad de establecer cada fila en la tabla a su altura individual correcta. Con cada fila a su altura correcta, la JTable en general termina siendo la altura correcta, lo que parece resolver el problema de truncamiento de impresión. El siguiente código muestra visitar todos los prestadores de hacer precisamente eso:

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); 
    } 
} 

Esta visitación manual de todos los procesadores de celdas no pasa por la optimización de la única invocación de los procesadores de celdas de células que aparecen en la pantalla del JTable. Como tal, es posible que desee ejecutar este código de solución después de que el usuario haya solicitado la impresión (pero antes de llamar al método de impresión en la JTable). Esto permite que la optimización de JTable permanezca vigente si el usuario solo está utilizando la GUI y no está imprimiendo.

+1

revés: el procesador de _must Not_ cambiar el estado de la persona que llama de ninguna manera, jamás. En su lugar, mueva la actualización de rowHeight al loop que está mostrando en esta publicación. – kleopatra

+0

@kleopatra - gracias por los comentarios. Me gustaría actualizar mi respuesta en respuesta a su comentario. Sin embargo, fui en busca de documentación de la regla "el procesador no debe cambiar el estado de la persona que llama", y no pude encontrar nada. No digo que estés equivocado, solo quiero leer más sobre eso y tal vez obtener la verificación. ¿Alguna idea sobre dónde está documentado este contrato? –

0

tuve que modificar ligeramente solución Mike Clarks para hacer que funcione para mí:

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); 
    } 
}