Swing中的TableCellRenderer与TableCellEditor的作用
2013-10-14 21:55
489 查看
受够了,Swing中的CellRenderer与CellEditor的作用,一直困扰着我,到了必须要熟悉的时候了!
下面三句话是读官方文档的最大收获,也是理解这两个概念的核心
The Renderer used to draw the data cells of the column using the specific compenent such as the JLabel, JCheckbox, and so on. 即界面在展示的时候调用的类
The Editor used to take over the cell, controlling the cell's editing behavior when the user start to edit the cell's data. 即当用户在点击单元格的时候,调用的类
BTW, the same cell, the Render and Editor could use the different compenet to react the behavior.
Render和Editor可以使用不同的组件对象,但一般都是一致的
关于上面这几点,首先阐述上面结论的出处仅将摘出重要的点,然后最后会有一个自定义的JCheckbox作为具体的实例,来理解这三点的应用和用处!
官方文档:
http://docs.oracle.com/javase/tutorial/uaiswing/components/table.html#editrender
Before you go on, you need to understand how tables draw their cells. You might expect each cell in a table to be a component. However, for
Instead,
a single cell renderer is generally used to draw all of the cells that contain the same type of data. You can think of therenderer as a configurable ink stamp that the table uses to stamp
appropriately formatted data onto each cell. When the user starts to edit a cell's data, a cell editor takes over the cell, controlling the cell's editing behavior.
For example, each cell in the # of Years column in
column uses a single
control the cell editing.
To choose the renderer that displays the cells in a column, a table first determines whether you specified a renderer for that particular column. If you did not, then the table invokes the table model's
which gets the data type of the column's cells. Next, the table compares the column's data type with a list of data types for which cell renderers are registered. This list is initialized by the table, but you can add to it or change it. Currently, tables
put the following types of data in the list:
a check box.
right-aligned label.
(using the default number format for the current locale).
label, with the object-to-text translation performed by a
and time).
label.
label that displays the object's string value.
Cell editors are chosen using a similar algorithm.
Remember that if you let a table create its own model, it uses
appropriately, as demonstrated by
Keep in mind that although renderers determine how each cell or column header looks and can specify its tool tip text, a renderer does not handle events. If
you need to pick up the events that take place inside a table, the technique you use varies by the sort of event you are interested in:
The next few sections tell you how to customize display and editing by specifying renderers and editors. You can specify cell renderers and editors either by column or by data type.
How to create and specify a cell renderer?
You can set a type-specific cell renderer using the
in a particular column should use a renderer, you use the
can even specify a cell-specific renderer by creating a
It is easy to customize the text or image rendered by the default renderer,
the appropriate string or image. For example, here is how the default date renderer is implemented:
If extending
of an existing component, making your subclass implement the
just one method:
下面是一个DefaultTableCellRenderer,自定义的CellRendderer一般都可继承它。
The standard class for rendering (displaying) individual cells in a JTable.
This class inherits from JLabel, a standard component class. However JTable employs a unique mechanism for rendering its cells and therefore requires some slightly modified behavior from its cell renderer.
The table class defines a single cell renderer and uses it as a as a rubber-stamp for rendering all cells in the table; it renders the first cell, changes the contents of that cell renderer, shifts the origin to the new location, re-draws it, and so on. The
standard JLabel component was not designed to be used this way and we want to avoid triggering a revalidate each time the cell is drawn. This would greatly decrease performance because the revalidate message would be passed up the hierarchy of the container
to determine whether any other components would be affected. As the renderer is only parented for the lifetime of a painting operation we similarly want to avoid the overhead associated with walking the hierarchy for painting operations. So this class overrides
the validate, invalidate, revalidate, repaint, and firePropertyChange methods to be no-ops and override the isOpaque method solely to improve performance. If you write your own renderer, please keep this performance consideration in mind.
DefaultTableCellRenderer继承自JLable,但是JTable使用一种独特的机制用来render单元格,因此需要在JLabel的基础上进行微调。Table类定义一种Cell Render,然后把它作为橡皮图章应用到所有的Cell中:首先render第一个单元格,修改Cell Render的内容,从原始位置迁移到新位置,重绘,等待。而标准JLabel组建并没有设计此用法,并且我们想要避免在每次Cell被绘制时触发一个revalidate。但这样会极大的降低性能,因为revalidate信息会沿着容器的继承关系传递直到有任何组件被影响。所以DefaultTableCellRenderer覆盖了validate,
invalidate,revalidate,repaint和firePropertyChange等方法以降低传递revalidate信息,并提高性能。
下面是具体的实例,对于Boolean的类型,JTabel有默认的CellRender和CellEditor但是,想要订制一种可以根据具体的Table中其他列的值要是否显示一个checkbox,下面就是一个具体的实例:
table.getColumnModel().getColumn(0).setCellEditor(new ChooseCellEditor());
table.getColumnModel().getColumn(0).setCellRenderer(new ChooseCellRenderer());
从getCellTableRendererComponent方法中可以看出每次Render的时候并不是都是一个JCheckBox,可以根据具体值,返回一个JLabel,而getCellTableEditorComponent方法也是如此,注意关于JCheckbox中的checkBox.setHorizontalAlignment(JLabel.CENTER);和checkBox.setBorderPainted(true);方法比较重要,因为决定了外观,读者可以试试,如果不加这两句话,或者Render中加,而Editor中不加是什么效果!
下面三句话是读官方文档的最大收获,也是理解这两个概念的核心
The Renderer used to draw the data cells of the column using the specific compenent such as the JLabel, JCheckbox, and so on. 即界面在展示的时候调用的类
The Editor used to take over the cell, controlling the cell's editing behavior when the user start to edit the cell's data. 即当用户在点击单元格的时候,调用的类
BTW, the same cell, the Render and Editor could use the different compenet to react the behavior.
Render和Editor可以使用不同的组件对象,但一般都是一致的
关于上面这几点,首先阐述上面结论的出处仅将摘出重要的点,然后最后会有一个自定义的JCheckbox作为具体的实例,来理解这三点的应用和用处!
官方文档:
http://docs.oracle.com/javase/tutorial/uaiswing/components/table.html#editrender
Before you go on, you need to understand how tables draw their cells. You might expect each cell in a table to be a component. However, for
performance reasons, Swing tables are implemented differently.
Instead,a single cell renderer is generally used to draw all of the cells that contain the same type of data. You can think of therenderer as a configurable ink stamp that the table uses to stamp
appropriately formatted data onto each cell. When the user starts to edit a cell's data, a cell editor takes over the cell, controlling the cell's editing behavior.
For example, each cell in the # of Years column in
TableDemocontains
Numberdata — specifically, an
Integerobject. By default, the cell renderer for a
Number-containing
column uses a single
JLabelinstance to draw the appropriate numbers, right-aligned, on the column's cells. If the user begins editing one of the cells, the default cell editor uses a right-aligned
JTextFieldto
control the cell editing.
To choose the renderer that displays the cells in a column, a table first determines whether you specified a renderer for that particular column. If you did not, then the table invokes the table model's
getColumnClassmethod,
which gets the data type of the column's cells. Next, the table compares the column's data type with a list of data types for which cell renderers are registered. This list is initialized by the table, but you can add to it or change it. Currently, tables
put the following types of data in the list:
Boolean— rendered with
a check box.
Number— rendered by a
right-aligned label.
Double,
Float— same as
Number, but the object-to-text translation is performed by a
NumberFormatinstance
(using the default number format for the current locale).
Date— rendered by a
label, with the object-to-text translation performed by a
DateFormatinstance (using a short style for the date
and time).
ImageIcon,
Icon— rendered by a centered
label.
Object— rendered by a
label that displays the object's string value.
Cell editors are chosen using a similar algorithm.
Remember that if you let a table create its own model, it uses
Objectas the type of every column. To specify more precise column types, the table model must define the
getColumnClassmethod
appropriately, as demonstrated by
TableDemo.java.
Keep in mind that although renderers determine how each cell or column header looks and can specify its tool tip text, a renderer does not handle events. If
you need to pick up the events that take place inside a table, the technique you use varies by the sort of event you are interested in:
Situation | How to Get Events |
---|---|
To detect events from a cell that is being edited... | Use the cell editor (or register a listener on the cell editor). |
To detect row/column/cell selections and deselections... | Use a selection listener as described in Detecting User Selections. |
To detect mouse events on a column header... | Register the appropriate type of mouse listener on the table's JTableHeaderobject. (See TableSorter.javafor an example.) |
To detect other events... | Register the appropriate listener on the JTableobject. |
How to create and specify a cell renderer?
You can set a type-specific cell renderer using the
JTablemethod
setDefaultRenderer. To specify thatcells
in a particular column should use a renderer, you use the
TableColumnmethod
setCellRenderer. You
can even specify a cell-specific renderer by creating a
JTablesubclass.
It is easy to customize the text or image rendered by the default renderer,
DefaultTableCellRenderer. You just create a subclass and implement the
setValuemethod so that it invokes
setTextor
setIconwith
the appropriate string or image. For example, here is how the default date renderer is implemented:
static class DateRenderer extends DefaultTableCellRenderer { DateFormat formatter; public DateRenderer() { super(); } public void setValue(Object value) { if (formatter==null) { formatter = DateFormat.getDateInstance(); } setText((value == null) ? "" : formatter.format(value)); } }
If extending
DefaultTableCellRendereris insufficient, you can build a renderer using another superclass. The easiest way is to create a subclass
of an existing component, making your subclass implement the
TableCellRendererinterface.
TableCellRendererrequires
just one method:
getTableCellRendererComponent. Your implementation of this method should set up the rendering component to reflect the passed-in state, and then return the component.
下面是一个DefaultTableCellRenderer,自定义的CellRendderer一般都可继承它。
DefaultTableCellRenderer
The standard class for rendering (displaying) individual cells in a JTable.
This class inherits from JLabel, a standard component class. However JTable employs a unique mechanism for rendering its cells and therefore requires some slightly modified behavior from its cell renderer.
The table class defines a single cell renderer and uses it as a as a rubber-stamp for rendering all cells in the table; it renders the first cell, changes the contents of that cell renderer, shifts the origin to the new location, re-draws it, and so on. The
standard JLabel component was not designed to be used this way and we want to avoid triggering a revalidate each time the cell is drawn. This would greatly decrease performance because the revalidate message would be passed up the hierarchy of the container
to determine whether any other components would be affected. As the renderer is only parented for the lifetime of a painting operation we similarly want to avoid the overhead associated with walking the hierarchy for painting operations. So this class overrides
the validate, invalidate, revalidate, repaint, and firePropertyChange methods to be no-ops and override the isOpaque method solely to improve performance. If you write your own renderer, please keep this performance consideration in mind.
DefaultTableCellRenderer继承自JLable,但是JTable使用一种独特的机制用来render单元格,因此需要在JLabel的基础上进行微调。Table类定义一种Cell Render,然后把它作为橡皮图章应用到所有的Cell中:首先render第一个单元格,修改Cell Render的内容,从原始位置迁移到新位置,重绘,等待。而标准JLabel组建并没有设计此用法,并且我们想要避免在每次Cell被绘制时触发一个revalidate。但这样会极大的降低性能,因为revalidate信息会沿着容器的继承关系传递直到有任何组件被影响。所以DefaultTableCellRenderer覆盖了validate,
invalidate,revalidate,repaint和firePropertyChange等方法以降低传递revalidate信息,并提高性能。
下面是具体的实例,对于Boolean的类型,JTabel有默认的CellRender和CellEditor但是,想要订制一种可以根据具体的Table中其他列的值要是否显示一个checkbox,下面就是一个具体的实例:
table.getColumnModel().getColumn(0).setCellEditor(new ChooseCellEditor());
table.getColumnModel().getColumn(0).setCellRenderer(new ChooseCellRenderer());
从getCellTableRendererComponent方法中可以看出每次Render的时候并不是都是一个JCheckBox,可以根据具体值,返回一个JLabel,而getCellTableEditorComponent方法也是如此,注意关于JCheckbox中的checkBox.setHorizontalAlignment(JLabel.CENTER);和checkBox.setBorderPainted(true);方法比较重要,因为决定了外观,读者可以试试,如果不加这两句话,或者Render中加,而Editor中不加是什么效果!
class ChooseCellRenderer extends JCheckBox implements TableCellRenderer, UIResource { private final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); public ChooseCellRenderer() { super(); setHorizontalAlignment(JLabel.CENTER); setBorderPainted(true); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Object fileName = table.getModel().getValueAt(row, 2); if (fileName == null) { return new JLabel(); } Object updator = table.getModel().getValueAt(row, 6); if (!updator.equals("张为云")) { return new JLabel(); } if (isSelected) { setForeground(table.getSelectionForeground()); super.setBackground(table.getSelectionBackground()); } else { setForeground(table.getForeground()); setBackground(table.getBackground()); } setSelected((value != null && ((Boolean) value).booleanValue())); if (hasFocus) { setBorder(UIManager.getBorder("Table.focusCellHighlightBorder")); } else { setBorder(noFocusBorder); } return this; } } class ChooseCellEditor extends DefaultCellEditor { public ChooseCellEditor() { super(new JCheckBox()); } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JCheckBox checkBox = (JCheckBox) getComponent(); checkBox.setHorizontalAlignment(JLabel.CENTER); checkBox.setBorderPainted(true); Object fileName = table.getModel().getValueAt(row, 2); if (fileName == null) { return new JLabel(); } Object updator = table.getModel().getValueAt(row, 6); if (!updator.equals("张为云")) { return new JLabel(); } return checkBox; } }
相关文章推荐
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- Java Swing JTable 表格【9:表格使用渲染器DefaultTableCellRenderer】
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- Java Swing JTable 表格【10:表格使用编辑器DefaultTableCellRenderer】
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- TablecellRenderer和TableCellEditor
- TableCellRenderer和TableCellEditor(一)
- TableCellRenderer和TableCellEditor
- TableCellRenderer & TableCellEditor(二)
- TableCellRenderer & TableCellEditor(三)
- 浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
- TablecellRenderer和TableCellEditor
- JTable的使用,以及使用JTextArea和DefaultTableCellRenderer达到居中或者多行显示的效果
- TableCellRenderer和DefaultTableCellRenderer
- DefaultTableCellRenderer 自定义
- 使用JCombox实现TableCellRenderer作为JTable的单元格例子
- 为JFace(TableViewer,TreeViewer...)创建可直接编辑的DialogCellEditor