Skip to content

Commit fdb6480

Browse files
hansonrhansonr
authored andcommitted
JTable performance enhancements
- default javax.swing renderers do not need to paint if no rows are selected. - renderers with a getComponent() method (rather than just a prepareRenderer(...) method) allows for single-pass preparation
1 parent d74a25c commit fdb6480

File tree

8 files changed

+261
-145
lines changed

8 files changed

+261
-145
lines changed

sources/net.sf.j2s.java.core/src/components/TableDemo.java

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,63 @@
3636
*/
3737

3838
import javax.swing.JFrame;
39+
import javax.swing.JLabel;
3940
import javax.swing.JPanel;
4041
import javax.swing.JScrollPane;
4142
import javax.swing.JTable;
43+
import javax.swing.border.LineBorder;
4244
import javax.swing.table.AbstractTableModel;
45+
import javax.swing.table.TableCellRenderer;
46+
47+
import components.TableDemo.DemoColor;
48+
49+
import java.awt.Color;
50+
import java.awt.Component;
4351
import java.awt.Dimension;
52+
import java.awt.Font;
53+
import java.awt.Graphics;
4454
import java.awt.GridLayout;
4555

4656
/**
4757
* TableDemo is just like SimpleTableDemo, except that it uses a custom
4858
* TableModel.
4959
*/
5060
public class TableDemo extends JPanel {
61+
public class ColorRenderer extends JLabel implements TableCellRenderer {
62+
63+
@Override
64+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
65+
int row, int column) {
66+
setOpaque(true);
67+
setBackground(colors[row % 3]);
68+
setText(" " + row);
69+
setBorder(new LineBorder(Color.white, 3));
70+
return this;
71+
}
72+
73+
public Component getComponent() {
74+
return this;
75+
}
76+
77+
}
78+
79+
static Color[] colors = new Color[] {Color.red, Color.blue, Color.green};
80+
81+
public class DemoColor {}
82+
83+
private DemoColor color = new DemoColor();
5184
private boolean DEBUG = false;
5285

5386
public TableDemo() {
5487
super(new GridLayout(1, 0));
5588

89+
5690
JTable table = new JTable(new MyTableModel());
5791
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
5892
table.setFillsViewportHeight(true);
5993

94+
table.setDefaultRenderer(DemoColor.class, new ColorRenderer());
95+
6096
// Create the scroll pane and add the table to it.
6197
JScrollPane scrollPane = new JScrollPane(table);
6298

@@ -65,31 +101,31 @@ public TableDemo() {
65101
}
66102

67103
class MyTableModel extends AbstractTableModel {
68-
private String[] columnNames = { "Row", "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };
104+
private String[] columnNames = { "Row", "Fav. Color", "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };
69105
private int i = 0;
70-
private Object[][] data = { { ++i, "Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false) },
71-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
72-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
73-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
74-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
75-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
76-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
77-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
78-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
79-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
80-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
81-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
82-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
83-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
84-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
85-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
86-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
87-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
88-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
89-
{ ++i, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
90-
{ ++i, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
91-
{ ++i, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
92-
{ ++i, "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };
106+
private Object[][] data = { { ++i, color, "Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false) },
107+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
108+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
109+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
110+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
111+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
112+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
113+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
114+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
115+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
116+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
117+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
118+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
119+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
120+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
121+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
122+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
123+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
124+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
125+
{ ++i, color, "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
126+
{ ++i, color, "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
127+
{ ++i, color, "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
128+
{ ++i, color, "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };
93129

94130
public int getColumnCount() {
95131
return columnNames.length;

sources/net.sf.j2s.java.core/src/javax/swing/JTable.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5562,6 +5562,11 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
55625562

55635563
return this;
55645564
}
5565+
5566+
public Component getComponent() {
5567+
return this;
5568+
}
5569+
55655570

55665571
}
55675572

sources/net.sf.j2s.java.core/src/javax/swing/table/DefaultTableCellRenderer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ public Component getTableCellRendererComponent(JTable table, Object value,
262262
return this;
263263
}
264264

265+
public Component getComponent() {
266+
return this;
267+
}
268+
265269
/*
266270
* The following methods are overridden as a performance measure to
267271
* to prune code-paths are often called in the case of renders

sources/net.sf.j2s.java.core/src/sun/swing/table/DefaultTableCellHeaderRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public Component getTableCellRendererComponent(JTable table, Object value,
128128

129129
return this;
130130
}
131-
131+
132132
public static SortOrder getColumnSortOrder(JTable table, int column) {
133133
SortOrder rv = null;
134134
if (table == null || table.getRowSorter() == null) {

sources/net.sf.j2s.java.core/src/swingjs/plaf/CellHolder.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22

33
import java.awt.JSComponent;
44

5-
import javax.swing.AbstractButton;
6-
import javax.swing.SwingConstants;
7-
import javax.swing.JTable.BooleanRenderer;
8-
import javax.swing.table.TableCellRenderer;
9-
105
import swingjs.api.js.DOMNode;
116

127
/**
@@ -18,7 +13,7 @@
1813
*/
1914
public abstract class CellHolder extends JSLightweightUI {
2015

21-
static String getRowColumnID(JSComponentUI holder, int row, int col) {
16+
static String getRowColumnID(JSComponentUI holder, int row, int col) {
2217
return holder.id + "_tab" + (row >= 0 ? "_row" + row : "") + "_col" + col;
2318
}
2419

@@ -56,10 +51,7 @@ static void updateCellNode(DOMNode td, JSComponent c, int width, int height) {
5651
ui.outerNode = null;
5752
ui.reInit();
5853
ui.updateDOMNode();
59-
ui.$(td).empty();
60-
td.appendChild(ui.domNode);
61-
ui.setCellNodes(td);
62-
ui.domNode = ui.outerNode = null;
54+
ui.saveCellNodes(td);
6355
}
6456

6557

sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,12 @@ public JComponent getTargetParent() {
180180
* When CellRendererPane updates a table cell, it needs to save and restore
181181
* all of the various nodes -- enableNode, textNode, etc -- to domNode.
182182
*
183+
* This save is done immediately after painting. It disables the ui for any
184+
* changes that might pass to it from property changes.
185+
*
183186
* @param td
184187
*/
185-
protected void setCellNodes(DOMNode td) {
188+
protected void saveCellNodes(DOMNode td) {
186189
DOMNode[] nodes = new DOMNode[] {
187190
domNode,
188191
innerNode,
@@ -203,10 +206,18 @@ protected void setCellNodes(DOMNode td) {
203206
scrollNode,
204207
};
205208
DOMNode.setAttr(td, "data-nodes", nodes);
209+
DOMNode node = DOMNode.firstChild(td);
210+
if (node != domNode) {
211+
$(td).empty();
212+
td.appendChild(domNode);
213+
}
214+
domNode = outerNode = null;
206215
}
207216

208-
protected void getCellNodes(DOMNode td) {
217+
protected void restoreCellNodes(DOMNode td) {
209218
DOMNode[] nodes = (DOMNode[]) DOMNode.getAttr(td, "data-nodes");
219+
if (nodes == null)
220+
return;
210221
domNode = nodes[0];
211222
innerNode = nodes[1];
212223
centeringNode = nodes[2];
@@ -229,6 +240,54 @@ protected void getCellNodes(DOMNode td) {
229240
}
230241

231242

243+
//
244+
// protected void setCellNodes(DOMNode td) {
245+
// DOMNode[] nodes = new DOMNode[] {
246+
// domNode,
247+
// innerNode,
248+
// centeringNode,
249+
//
250+
// iconNode,
251+
// textNode,
252+
// buttonNode,
253+
// enableNode,
254+
//
255+
// (enableNodes == null ? null : enableNodes[0]),
256+
// (enableNodes == null ? null : enableNodes[1]),
257+
// (enableNodes == null ? null : enableNodes[2]),
258+
//
259+
// focusNode,
260+
// actionNode,
261+
// valueNode,
262+
// scrollNode,
263+
// };
264+
// DOMNode.setAttr(td, "data-nodes", nodes);
265+
// }
266+
//
267+
// protected void getCellNodes(DOMNode td) {
268+
// DOMNode[] nodes = (DOMNode[]) DOMNode.getAttr(td, "data-nodes");
269+
// domNode = nodes[0];
270+
// innerNode = nodes[1];
271+
// centeringNode = nodes[2];
272+
//
273+
// iconNode = nodes[3];
274+
// textNode = nodes[4];
275+
// buttonNode = nodes[5];
276+
// enableNode = nodes[6];
277+
//
278+
// if (nodes[7] != null) {
279+
// enableNodes[0] = nodes[7];
280+
// enableNodes[1] = nodes[8];
281+
// enableNodes[2] = nodes[9];
282+
// }
283+
//
284+
// focusNode = nodes[10];
285+
// actionNode = nodes[11];
286+
// valueNode = nodes[12];
287+
// scrollNode = nodes[13];
288+
// }
289+
//
290+
232291

233292
/**
234293
* inner node for JButtonUI that needs to be cleared prior to calculating
@@ -339,11 +398,6 @@ public void setDraggable(JSFunction f) {
339398
J2S.setDraggable(getDOMNode(), f);
340399
}
341400

342-
/**
343-
* label for JLabel; null for JSTooltipUI subclass of JSLabelUI
344-
*/
345-
protected JLabel label;
346-
347401
/**
348402
* a numerical reference for an ID
349403
*/
@@ -546,6 +600,9 @@ private void uninstallJS() {
546600
private void setComponent(JComponent comp) {
547601
c = jc = comp;
548602
isUIDisabled = (comp == null);
603+
if (isUIDisabled)
604+
domNode = outerNode = null;
605+
549606
}
550607

551608
public JSComponentUI set(JComponent target) {

sources/net.sf.j2s.java.core/src/swingjs/plaf/JSLabelUI.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public class JSLabelUI extends JSLightweightUI {
2323
protected int gap;
2424
protected String text;
2525

26+
/**
27+
* label for JLabel; null for JSTooltipUI subclass of JSLabelUI
28+
*/
29+
private JLabel label;
30+
31+
2632
public JSLabelUI() {
2733
setDoc();
2834
}

0 commit comments

Comments
 (0)