我有一个带有自定义单元格渲染器的JTable。该单元格是一个包含JTextField和JButton的JPanel。 JTextField包含一个整数,当用户点击JButton时,整数应该增加。
问题是当我在JTable单元格中使用它时,无法单击JButton。如何点击它?
这是我的测试代码:
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;
}
}
}
答案 0 :(得分:9)
这是使用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 "-";
}
}
}
答案 1 :(得分:7)
我的最后一个例子是基于mKrobels回答How to implement dynamic GUI in swing
提供的代码他和我在问题中的例子之间的主要区别在于他使用DefaultTableModel
而我使用AbstractTableModel
。他的榜样确实有效,但不是我的。
我找到的解决方案是我必须在TableModel中实现isCellEditable()
,所以添加了这个方法,我的示例有效:
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
答案 2 :(得分:3)
渲染器只是用于绘制单元格的显示。您需要一个允许您进行更改的编辑器组件。
看看:
http://download.oracle.com/javase/6/docs/api/javax/swing/table/TableCellEditor.html