【问题标题】:JXTable: use a TableCellEditor and TableCellRenderer for a specific cell instead of the whole columnJXTable:对特定单元格而不是整个列使用 TableCellEditor 和 TableCellRenderer
【发布时间】:2014-10-02 07:19:27
【问题描述】:

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

然后我意识到我的自定义编辑器和渲染器同时更改了所有列组件,而不仅仅是所需的组件。 所以,我尝试在TableCellEditorTableCellRendererPropertyChangeListener 中进行更改,但我还是想不通。

【问题讨论】:

  • J(X)Table 已将 JCheckBox 实现为 Renderer/Editor,剩下的问题是关于模型中的方法,例如setValueAt 应该是

标签: java swing tablecellrenderer tablecelleditor jxtable


【解决方案1】:

首先请注意,您的问题与 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() 方法才能根据第一个布尔值正确更新第二个布尔值列。例如考虑这个 sn-p:

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

【讨论】:

    猜你喜欢
    • 2013-08-13
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 2013-08-17
    • 1970-01-01
    相关资源
    最近更新 更多