2011-02-04 10 views
5

Mam JTable, który używa JTextArea jako jego TableCellRenderer, tak aby komórki tabeli można wykorzystać zawijanie wyrazów. JTable wyświetla się dobrze. Kiedy wydrukuję tabelę na drukarkę za pomocą JTable's print method, dane wyjściowe są zawsze przycinane na około 60% danych. Próbowałem różnych komputerów i różnych drukarek oraz różnych sterowników drukarki, różnych wersji JVM (1.5, 1.6), ale nic z tego nie pomogło. Poniżej znajduje się samodzielna główna klasa Java, która odtwarza problem. Jakieś pomysły?Skrócone JTable print output

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

Odpowiedz

0

Wierzę, że znalazłem podstawową przyczynę i rozwiązanie. Problem z drukowaniem wynika z faktu, że stół ma niewłaściwą wysokość. Stół ma niewłaściwą wysokość, ponieważ niektóre wiersze tabeli mają niewłaściwą wysokość. Niektóre wiersze mają niewłaściwą wysokość, ponieważ ich renderery komórek nie zostały wywołane przez JTable (to znaczy, że ich metoda getTableCellRendererComponent nie została wywołana.) Powodem, dla którego JTable pomija niektóre z renderers komórek jest optymalizacja - renderowanie komórek pomija są dla komórek, które są poza ekranem - poza ekranem oznacza, że ​​renderowanie nie jest potrzebne; Optymalizacja JTable w tym obszarze ma sens.

Jednak renderery są jedynym miejscem w programie, w którym ustawiona jest prawidłowa wysokość każdego pojedynczego wiersza. Mój wybór, aby ustawić wysokość wiersza w rendererze komórek, jest dość zrozumiały, ponieważ mechanizm renderujący komórki jest w najlepszej pozycji, aby wiedzieć, jaka powinna być wysokość wiersza.

Wydaje się, że najprostszym sposobem naprawy tego przykładowego programu jest ręczne wywołanie getTableCellRendererComponent na każdym rendererze komórek (należy to zrobić po zmodyfikowaniu danych modelu tabeli). Daje to renderers możliwość ustawienia każdego wiersza w tabeli do właściwej wysokości. Przy każdym rzędzie na prawidłowej wysokości, JTable ogólnie kończy się na odpowiedniej wysokości, co wydaje się rozwiązywać problem obcięcia druku. Poniższy kod pokazuje zwiedzanie wszystkich renderujące właśnie do tego:

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

Niniejsza instrukcja wizytacja wszystkich renderujących komórkowych omija optymalizacji JTable dotyczącą tylko powołując się na renderujące komórkowe komórek na ekranie. Jako taki, możesz chcieć wykonać ten kod tylko wtedy, gdy użytkownik zażąda drukowania (ale przed wywołaniem metody drukowania na JTable). Dzięki temu optymalizacja JTable będzie obowiązywać, jeśli użytkownik użyje interfejsu GUI, a nie drukowania.

+1

niewłaściwy sposób okrągłe: renderer _must not_ zmiany stanu rozmówcy w żaden sposób, nigdy. Zamiast tego przenieś aktualizację RowHeight do pętli, którą wyświetlasz w tym poście. – kleopatra

+0

@kleopatra - dziękuję za informację zwrotną. Chciałbym zaktualizować moją odpowiedź w odpowiedzi na Twój komentarz. Jednak poszedłem szukać dokumentacji reguły "renderer nie może zmienić stanu dzwoniącego" i nie mogłem nic znaleźć. Nie mówię, że się mylisz - chcę tylko przeczytać więcej na ten temat i być może uzyskać weryfikację. Jakieś pomysły na temat tego, gdzie dokumentowana jest ta umowa? –

0

musiałem lekko zmodyfikować rozwiązanie Mike Clarks, aby pracować dla mnie:

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