JXTable:对特定单元格而不是整列使用TableCellEditor和TableCellRenderer [英] JXTable: use a TableCellEditor and TableCellRenderer for a specific cell instead of the whole column
问题描述
我有一个 JXTable
6列的复合词,其中两列是 JCheckBox
。我希望有以下行为:
I have a JXTable
compound of 6 columns and two of them are JCheckBox
. I would like to have the following behavior:
- 如果选中第一个复选框,则启用第二个复选框,可以检查或不检查。
- 如果第一个复选框未选中,则必须禁用第二个复选框并取消选中。
I使用Photoshop编辑图像以显示所需结果:
I edited an image with Photoshop to show the desired result:
对于 CheckOne
和 CheckTwo
列,我使用自定义 TableCellEditor
和 TableCellRenderer
:
For the CheckOne
and CheckTwo
columns i use a custom TableCellEditor
and TableCellRenderer
:
public class CheckBoxCellEditor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
private JCheckBox checkBox = new JCheckBox();
public CheckBoxCellEditor() {
checkBox.setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
checkBox.setSelected(value==null ? false : (boolean)value);
return checkBox;
}
@Override
public Object getCellEditorValue() {
return checkBox.isSelected();
}
}
public class CheckBoxCellRenderer extends JCheckBox implements TableCellRenderer{
private static final long serialVersionUID = 1L;
public CheckBoxCellRenderer() {
setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setSelected(value==null ? false : (boolean)value);
return this;
}
}
这就是我设置它们的方式:
And this is how i set them:
//CheckOne
table.getColumn(4).setCellEditor(new CheckBoxCellEditor());
table.getColumn(4).setCellRenderer(new CheckBoxCellRenderer());
//CheckTwo
table.getColumn(5).setCellEditor(new CheckBoxCellEditor());
table.getColumn(5).setCellRenderer(new CheckBoxCellRenderer());
我试图将 PropertyChangeListener
添加到 JXTable
并从那里实现行为,但我无法完成它。
I tried to add a PropertyChangeListener
to the JXTable
and implement the behavior from there, but i couldn´t get it done.
然后我意识到我的自定义编辑器和渲染器同时更改了所有列组件,而不仅仅是所需的组件。
所以,我试图在 TableCellEditor
和 TableCellRenderer
中进行更改,并在<$ c中进行更改$ c> PropertyChangeListener 但是,再次,我无法弄明白。
Then i realised that my custom editor and renderer were changing all the column components at the same time instead of only the desired component.
So, i tried to make the changes in the TableCellEditor
and TableCellRenderer
, and in the PropertyChangeListener
but, again, i couldn´t figure it out.
推荐答案
首先关闭请注意您的问题与JXTable无关,但与渲染器/编辑器/模型无关。
First off please note your problem is not related to JXTable but renderers / editors / model.
正如@mKorbel指出JCheckBox是布尔值的默认渲染器/编辑器,一般来说你赢了不需要重新发明轮子:只需覆盖 getColumnClass()正确返回第5列和第6列的布尔值。
As @mKorbel points out JCheckBox is the default Renderer/Editor for booleans and generally speaking you won't need to re-invent the wheel: just override getColumnClass() properly to return Boolean on both 5th and 6th columns.
但是,由于此要求:
如果第一个复选框未选中,则第二个复选框必须禁用且未选中。
If the first checkbox is unchecked, the second must be disabled and unchecked.
这不是默认渲染器的行为,所以你实际上需要你自己的渲染器。 但只有渲染器,你不需要编辑器:因为@mKorbel指出你需要对表模型进行一些工作。
This is not the default renderer's behavior so you actually need your own renderer. But only renderer, you don't need an editor: as @mKorbel points out you need a little work with the table model.
class CheckBoxCellRenderer implements TableCellRenderer {
private final JCheckBox renderer;
public CheckBoxCellRenderer() {
renderer = new JCheckBox();
renderer.setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Color bg = isSelected
? table.getSelectionBackground() : table.getBackground();
renderer.setBackground(bg);
renderer.setEnabled(table.isCellEditable(row, column));
renderer.setSelected(value != null && (Boolean)value);
return renderer;
}
}
型号
您需要同时处理 isCellEditable()和 setValueAt()方法根据第一个布尔值正确更新您的第二个布尔值列。例如,请考虑以下代码段:
Model
You need to work on both isCellEditable() and setValueAt() methods to properly update your second booleans column based on values on first one. For instance consider this snippet:
// A default model with 5 rows and 6 columns
DefaultTableModel model = new DefaultTableModel(5, 6) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case 4:
case 5: return Boolean.class; // Both 5th and 6th columns are booleans
}
return super.getColumnClass(columnIndex);
}
@Override
public boolean isCellEditable(int row, int column) {
/*
* In order to know if 6th column is editable, you have to check
* 5th column's value.
*/
if(column == 5) {
Object value = getValueAt(row, 4);
return value != null && (Boolean)value;
}
return super.isCellEditable(row, column);
}
@Override
public void setValueAt(Object aValue, int row, int column) {
/*
* If 5th column value is updated to FALSE, you need to
* set 6th column's value to FALSE as well
*/
if(column == 4) {
super.setValueAt(Boolean.FALSE, row, 5);
}
super.setValueAt(aValue, row, column);
}
};
测试
这是一个完整的测试用例。希望它有所帮助。
Test it
Here is a complete test case. Hope it helps.
import java.awt.Color;
import java.awt.Component;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
/**
* @author dic19
*/
public class Demo {
private void createAndShowGui() {
DefaultTableModel model = new DefaultTableModel(5, 6) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case 4:
case 5: return Boolean.class;
}
return super.getColumnClass(columnIndex);
}
@Override
public boolean isCellEditable(int row, int column) {
if(column == 5) {
Object value = getValueAt(row, 4);
return value != null && (Boolean)value;
}
return super.isCellEditable(row, column);
}
@Override
public void setValueAt(Object aValue, int row, int column) {
if(column == 4) {
super.setValueAt(false, row, 5);
}
super.setValueAt(aValue, row, column);
}
};
JTable table = new JTable(model);
table.getDefaultRenderer(null);
table.getColumnModel().getColumn(5).setCellRenderer(new CheckBoxCellRenderer());
JScrollPane scrollPane = new JScrollPane(table);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
class CheckBoxCellRenderer implements TableCellRenderer {
private final JCheckBox renderer;
public CheckBoxCellRenderer() {
renderer = new JCheckBox();
renderer.setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Color bg = isSelected
? table.getSelectionBackground() : table.getBackground();
renderer.setBackground(bg);
renderer.setEnabled(table.isCellEditable(row, column));
renderer.setSelected(value != null && (Boolean)value);
return renderer;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Demo().createAndShowGui();
}
});
}
}
这篇关于JXTable:对特定单元格而不是整列使用TableCellEditor和TableCellRenderer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!