JXTable:对特定单元格而不是整列使用TableCellEditor和TableCellRenderer

我有一个6列的JXTable复合,其中两个是JCheckBox 。 我想有以下行为:

  • 如果选中第一个复选框,则启用第二个复选框,可以检查或不检查。
  • 如果未选中第一个复选框,则必须禁用并取消选中第二个复选框。

我用Photoshop编辑了一个图像以显示所需的结果: 在此处输入图像描述

对于CheckOneCheckTwo列,我使用自定义TableCellEditorTableCellRenderer

 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; } } 

这就是我设置它们的方式:

 //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并从那里实现行为,但我无法完成它。

然后我意识到我的自定义编辑器和渲染器同时更改了所有列组件,而不是仅更改所需的组件。 所以,我试图在TableCellEditorTableCellRenderer进行更改,并在PropertyChangeListener进行更改,但是,再次,我无法弄明白。

首先请注意您的问题与JXTable无关,但与渲染器/编辑器/模型无关。

正如@mKorbel指出JCheckBox是布尔值的默认渲染器/编辑器,一般来说你不需要重新发明轮子:只需正确覆盖getColumnClass()以在第5和第6列返回布尔值。

但是,由于这个要求:

如果未选中第一个复选框,则必须禁用并取消选中第二个复选框。

这不是默认渲染器的行为,因此您实际上需要自己的渲染器。 只有渲染器,你不需要编辑器:因为@mKorbel指出你需要对表模型进行一些工作。

渲染

 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()方法,以根据第一个上的值正确更新第二个布尔值列。 例如,请考虑以下代码段:

 // 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); } }; 

测试一下

这是一个完整的测试用例。 希望能帮助到你。

 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(); } }); } }