JTable Calls Método personalizado de procesamiento de celdas … Continuamente

La fuente comstackble se puede encontrar en: http://www.splashcd.com/jtable.tar

Soy nuevo en el idioma, por lo que no estoy seguro si este es un comportamiento aceptable o no.

Creé una JTable para mostrar una fila por cada mensaje recibido (recibe aproximadamente uno cada 20 segundos). Una de las columnas de la tabla puede contener una gran cantidad de texto, por lo que creé un procesador de celdas personalizado cuya palabra se ajusta y establece la altura de la fila en consecuencia.

Todo eso funciona como se espera, excepto que una vez que la tabla muestra su primera fila, llama al procesador de la celda unas diez veces por segundo … hasta que el usuario cierra la tabla.

Una vez que obtengo aproximadamente 20 filas allí, la tabla se pone bastante lenta, tarda de 2 a 8 segundos en cambiar el tamaño de una columna, boost o disminuir, o renderizar una fila seleccionada con el color de fondo seleccionado.

Inserté una statement de impresión dentro del renderizador, por lo que puedo ver cuántas veces se está llamando al método getTableCellRendererComponent.

Deshabilité las sugerencias de herramientas y deshabilité todas las ediciones de las celdas. Tengo un oyente que desplaza la vista a la última fila cuando se agrega una nueva fila o se cambia el tamaño de la tabla.

¿Debería llamarse el método getTableCellRendererComponent varias veces por segundo cuando estoy viendo la pantalla (sin tocar el mouse o el teclado)?

TIA

  • aaaaach

  • necesitas doLayout() ,

  • siguiente nivel :-), luego puedes establecer Maximum visible row para JTextComponents también, con poco esfuerzo

enter image description here

doLayout ()

 import java.awt.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.text.*; //http://tips4java.wordpress.com/2008/10/26/text-utilities/ public class AutoWrapTest { public JComponent makeUI() { String[] columnNames = {" Text Area Cell Renderer "}; Object[][] data = { {"123456789012345678901234567890"}, {"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"}, {"----------------------------------------------0"}, {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddxdddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddddddx>>>>>>>>>>>>>>>>>>>>>>>>>|"}, {">>>>>>>>>>>>ddddddddddddddddddddddddddddddddddddddddddddddddddd" + "ddddddx>>>>>>>>>>>>>>>>>>>>>>>>>>|"}, {"a|"}, {">>>>>>>>bbbb>>>>>>>>>>>>>>>>>>>|"}, {">>>>>>>>>>>>>>>>>>|"}, {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddxdddddddddddddd123456789012345678901234567890dddddd" + "dddddddddddddddddddddddddddddddddddddx>>>>>>>>>>>>>>>>>>>>" + ">>>>>|"}, {">>>>>>>>>>>>>dddddddddddddd123456789012345678901234567890dddddd" + "dddddddddddddddddddddddddddddddddddddxdddddddddddddd123456" + "789012345678901234567890dddddddddddddddddddddddddddddddddd" + "ddddd123456789012345678901234567890ddddx>>>>>>>>>>>>>>>>>>" + ">>>>>>>|"},}; TableModel model = new DefaultTableModel(data, columnNames) { private static final long serialVersionUID = 1L; @Override public boolean isCellEditable(int row, int column) { return false; } }; JTable table = new JTable(model) { private static final long serialVersionUID = 1L; @Override public void doLayout() { TableColumn col = getColumnModel().getColumn(0); for (int row = 0; row < getRowCount(); row++) { Component c = prepareRenderer(col.getCellRenderer(), row, 0); if (c instanceof JTextArea) { JTextArea a = (JTextArea) c; int h = getPreferredHeight(a) + getIntercellSpacing().height; if (getRowHeight(row) != h) { setRowHeight(row, h); } } } super.doLayout(); } private int getPreferredHeight(JTextComponent c) { Insets insets = c.getInsets(); View view = c.getUI().getRootView(c).getView(0); int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS); return preferredHeight + insets.top + insets.bottom; } }; table.setEnabled(false); table.setShowGrid(false); table.setTableHeader(null); table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer()); //table.setPreferredScrollableViewportSize(table.getPreferredSize()); JScrollPane sp = new JScrollPane(table); sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); sp.setPreferredSize(new Dimension(250, 533)); JPanel p = new JPanel(new BorderLayout()); p.add(sp); return p; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } public static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new AutoWrapTest().makeUI()); f.setLocation(100, 100); f.pack(); f.setVisible(true); } } class TextAreaCellRenderer extends JTextArea implements TableCellRenderer { private static final long serialVersionUID = 1L; private final Color evenColor = new Color(230, 240, 255); public TextAreaCellRenderer() { super(); setLineWrap(true); setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } else { setForeground(table.getForeground()); setBackground(table.getBackground()); setBackground((row % 2 == 0) ? evenColor : getBackground()); } setFont(table.getFont()); setText((value == null) ? "" : value.toString()); return this; } } 

Para obtener el máximo rendimiento de un TableCellRenderer , asegúrese de no crear una nueva instancia de un componente cada vez que se getTableCellRenderer . Haga los componentes una vez y guárdelos como campos de la clase.

Además, querrá asegurarse de que cada uno de los componentes que utiliza tenga los siguientes métodos anulados para no hacer nada:

  • validar
  • invalidar
  • revalidar
  • volver a pintar
  • firePropertyChange

(y es probable que desee un código difícil isOpaque ).

Para obtener más información, consulte: http://docs.oracle.com/javase/6/docs/api/javax/swing/tree/DefaultTreeCellRenderer.html

El problema parece provenir de tener setRowHeight () de JTable dentro del renderizador de células personalizadas, ya que llama al renderizador de células personalizado, lanzándolo a un bucle infinito.

Tuve que agregar un cheque para ver si la altura de la fila actual coincidía con la altura calculada de la altura envuelta de la palabra. Si lo hizo, no intenté volver a configurarRowHeight () nuevamente.

Código corregido:

 import java.awt.Component; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.UIManager; import javax.swing.table.TableCellRenderer; //custom cell renderer for word wrapping, but if you use, you have to //implement zebra striping functionality which the default renderer has public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer { private int numOfTimesCalled; @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { System.out.println("Line Wrap Cell Renderer Called: " + numOfTimesCalled++); System.out.println("row:"+ row + ", col:" + column); //set up the row size based on the number of newlines in the text in the cell int fontHeight = this.getFontMetrics(this.getFont()).getHeight(); int numWraps = value.toString().split("\r\n|\r|\n").length; int rowHeight = fontHeight * numWraps; //if the calculated rowHeight is the same as the row height of row, // then don't call setRowHeight again, as doing so will throw us into // an infinite loop if(rowHeight != table.getRowHeight(row)) { table.setRowHeight(row, rowHeight); //configure word wrapping setWrapStyleWord(true); setLineWrap(true); //use the table's font setFont(table.getFont()); } //zebra striping, because whatever cell uses this renderer loses the //default cell renderer zebra striping if(isSelected) { setBackground(table.getSelectionBackground()); } else { if(row%2 == 1) { setBackground(UIManager.getColor("Table.alternateRowColor")); } else { setBackground(table.getBackground()); } } this.setText(value.toString()); return this; } }