JTable Calls Custom Cell Renderer Method ... Continuous

The compiled source can be found at: http://www.splashcd.com/jtable.tar

I am new to the language, so I'm not sure if this is acceptable behavior or not.

I created a JTable to display a line for each message received (it receives once every 20 seconds). One of the columns of the table may contain a large amount of text, so I created my own cell handler that wraps the word and sets the line height accordingly.

Everything that works is as expected, except that as soon as the table displays its first row, it calls the cell renderer about ten times per second ... until the user closes the table.

As soon as I get about 20 rows, the table becomes rather sluggish, taking 2-8 seconds to resize the column, scoll up or down or display the selected row using the selected background color.

I inserted a print statement inside the renderer, so I can see how many times the getTableCellRendererComponent method is called.

I disabled tooltips and disabled all cell editing. I have a listener that scrolls the view to the last row when a new row is added or the table is changed.

Should the getTableCellRendererComponent method be called several times per second when I just view the screen (without touching the mouse or keyboard)?

TIA

+5
source share
3 answers
  • aaaaach

  • you need doLayout() ,

  • Next level :-), then you can set the Maximum visible row for JTextComponents too, with little effort

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; } } 
+9
source

To get maximum performance from TableCellRenderer , make sure that you do not create a new instance of the component each time getTableCellRenderer is getTableCellRenderer . Make components once and save them as class fields.

In addition, you must make sure that each of the components that you use has the following methods overridden in order to do nothing:

  • Validate
  • Invalidate
  • REVALIDATE
  • repaint
  • firePropertyChange

(and you probably need isOpaque hard code).

For more information see http://docs.oracle.com/javase/6/docs/api/javax/swing/tree/DefaultTreeCellRenderer.html

+2
source

The problem seems to be due to the presence of JTable setRowHeight () inside the custom cell renderer, as it invokes the custom cell renderer, throwing it into an infinite loop.

I had to add a check to see if the current line height matches the calculated word collapsed into a line. If so, I have not tried to install RowHeight () again.

Corrected Code:

 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 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; } } 
+1
source

Source: https://habr.com/ru/post/973122/


All Articles