简体   繁体   English

如何使 JTable 单元格中的 JButton 可点击?

[英]How to make a JButton in a JTable cell click-able?

I have a JTable with a custom cell renderer.我有一个带有自定义单元格渲染器的 JTable。 The cell is a JPanel that contains a JTextField and a JButton.该单元格是一个 JPanel,其中包含一个 JTextField 和一个 JButton。 The JTextField contains an integer, and when the user clicks on the JButton the integer should be increased. JTextField 包含一个整数,当用户单击 JButton 时,该整数应该增加。

The problem is that the JButton can't be clicked when I have it in a JTable cell.问题是当我将 JButton 放在 JTable 单元格中时无法单击它。 How can I make it click-able?我怎样才能让它可点击?

在此处输入图片说明

Here is my test code:这是我的测试代码:

public class ActiveTable extends JFrame {

    public ActiveTable() {
        RecordModel model = new RecordModel();
        model.addRecord(new Record());
        JTable table = new JTable(model);
        EditorAndRenderer editorAndRenderer = new EditorAndRenderer();
        table.setDefaultRenderer(Object.class, editorAndRenderer);
        table.setDefaultEditor(Object.class, editorAndRenderer);
        table.setRowHeight(38);

        add(new JScrollPane(table));
        setPreferredSize(new Dimension(600, 400));
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("Active Table");
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ActiveTable();
            }
        });
    }

    class RecordModel extends AbstractTableModel {

        private final List<Record> records = new ArrayList<Record>();

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public int getRowCount() {
            return records.size();
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return records.get(rowIndex);
        }

        public void addRecord(Record r) {
            records.add(r);
            fireTableRowsInserted(records.size()-1, records.size()-1);
        }

    }

    class Record {
        private int count = 1;
        public int getCount() { return count; }
        public void increase() { count = count + 1; }
    }

    class CellPanel extends JPanel {
        private Record record;
        private final JTextField field = new JTextField(8);
        private final Action increaseAction = new AbstractAction("+") {
            public void actionPerformed(ActionEvent e) {
                record.increase();
                field.setText(record.getCount()+"");
                JTable table = (JTable) SwingUtilities.getAncestorOfClass(JTable.class, (Component) e.getSource());
                table.getCellEditor().stopCellEditing();
            }
        };
        private final JButton button = new JButton(increaseAction);

        public CellPanel() {
            add(field);
            add(button);
        }

        public void setRecord(Record r) {
            record = r;
            field.setText(record.getCount()+"");
        }

        public Record getRecord() {
            return record;
        }
    }

    class EditorAndRenderer extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private final CellPanel renderer = new CellPanel();
        private final CellPanel editor = new CellPanel();

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
            renderer.setRecord((Record) value);
            return renderer;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {
            editor.setRecord((Record) value);
            return editor;
        }

        @Override
        public Object getCellEditorValue() {
            return editor.getRecord();
        }

        @Override
        public boolean isCellEditable(EventObject ev) {
            return true;
        }

        @Override
        public boolean shouldSelectCell(EventObject ev) {
            return false;
        }
    }
}

Here's one way to use ButtonColumn .这是使用ButtonColumn的一种方法。

public class TableTest extends JFrame {

    public TableTest() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTable table = new JTable(new TestModel());
        table.getColumnModel().getColumn(1).setPreferredWidth(3);
        table.getColumnModel().getColumn(2).setPreferredWidth(3);
        this.add(new JScrollPane(table));
        Action increase = new AbstractAction("+") {

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.increment(row, 0);
            }
        };
        ButtonColumn inc = new ButtonColumn(table, increase, 1);
        Action decrease = new AbstractAction("-") {

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.decrement(row, 0);
            }
        };
        ButtonColumn dec = new ButtonColumn(table, decrease, 2);
        pack();
    }

    public static void main(String[] args) {
        new TableTest().setVisible(true);
    }
}

class TestModel extends AbstractTableModel {

    List<TestRecord> records = new LinkedList<TestRecord>();

    private static class TestRecord {

        private int val = 0;
    }

    public void increment(int row, int col) {
        records.get(row).val++;
        fireTableCellUpdated(row, 0);
    }

    public void decrement(int row, int col) {
        records.get(row).val--;
        fireTableCellUpdated(row, 0);
    }

    public TestModel() {
        records.add(new TestRecord());
        records.add(new TestRecord());
    }

    @Override
    public Class<?> getColumnClass(int col) {
        if (col == 0) {
            return Integer.class;
        } else {
            return ButtonColumn.class;
        }
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return true;
    }

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public int getRowCount() {
        return records.size();
    }

    @Override
    public Object getValueAt(int row, int col) {
        if (col == 0) {
            return records.get(row).val;
        } else if (col == 1) {
            return "+";
        } else {
            return "-";
        }
    }
}

I based my last example on the code provided by mKrobels answer to How to implement dynamic GUI in swing我的最后一个示例基于 mKrobels 对如何在摆动中实现动态 GUI 的回答提供的代码

The main difference between his and my example in the question is that he use DefaultTableModel and I use AbstractTableModel .他和我在问题中的示例之间的主要区别是他使用DefaultTableModel而我使用AbstractTableModel His example does work, but not mine.他的例子确实有效,但不是我的。

The solution I found was that I had to implement isCellEditable() in the TableModel, so with this method added, my example works:我发现的解决方案是我必须在 TableModel 中实现isCellEditable() ,所以添加了这个方法后,我的例子就可以工作了:

@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
    return true;
}

The renderer is just a display for painting the cells.渲染器只是用于绘制单元格的显示器。 You need an editor component that allows you to make changes.您需要一个允许您进行更改的编辑器组件。

Take a look at:看一眼:

http://download.oracle.com/javase/6/docs/api/javax/swing/table/TableCellEditor.html http://download.oracle.com/javase/6/docs/api/javax/swing/table/TableCellEditor.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM