我尝试实现一个具有某些字段和删除按钮的TableCellEditor。它运行良好,但删除行时,已删除单元格中的内容(使用TableCellEditor呈现)不更新。
当删除行时,我试图在模型中同时调用fireTableRowsDeleted(row, row)
和fireTableDataChanged()
,但它似乎没有通知TableCellEditor。它在我选择另一行时有效,并且再次使用TableCellRenderer呈现行索引。
有关如何在删除时通知TableCellEditor的任何建议?
按下删除按钮
已删除行,但未更新CellEditor内容
当再次使用CellRenderer时,行内容已更新。
以下是代码:
public class StringTableDemo extends JFrame {
public StringTableDemo() {
final StringTableModel model = new StringTableModel();
model.addRow("Jonas");
model.addRow("Hello");
model.addRow("World");
RendererAndEditor rendererAndEditor = new RendererAndEditor(model);
JTable table = new JTable(model);
table.setDefaultRenderer(Record.class, rendererAndEditor);
table.setDefaultEditor(Record.class, rendererAndEditor);
add(new JScrollPane(table), BorderLayout.CENTER);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
class Record {
String string;
boolean isDeleted;
}
class StringTableModel extends AbstractTableModel {
private final List<Record> data = new ArrayList<Record>();
@Override
public int getColumnCount() {
return 1;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int row, int column) {
return data.get(row);
}
@Override
public Class<?> getColumnClass(int column) {
return Record.class;
}
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
@Override
public void setValueAt(Object aValue, int row, int column) {
if(aValue instanceof Record) {
Record r = (Record)aValue;
if(!r.isDeleted) {
data.set(row, r);
fireTableRowsUpdated(row, column);
}
} else throw new IllegalStateException("aValue is not a Record");
}
public void addRow(String s) {
Record r = new Record();
r.string = s;
r.isDeleted = false;
data.add(r);
fireTableRowsInserted(data.size()-1, data.size()-1);
}
public void removeRow(int row) {
data.remove(row);
//fireTableRowsDeleted(row, row);
fireTableDataChanged();
System.out.println("row " + row + " deleted");
}
}
class CellPanel extends JPanel {
private final Action removeAction = new AbstractAction("x") {
@Override
public void actionPerformed(ActionEvent arg0) {
model.removeRow(index);
isDeleted = true;
}
};
private final JButton removeBtn = new JButton(removeAction);
private final JTextField field = new JTextField();
private final StringTableModel model;
private int index;
private boolean isDeleted = false;
public CellPanel(StringTableModel model) {
super(new BorderLayout());
this.model = model;
add(field, BorderLayout.CENTER);
add(removeBtn, BorderLayout.EAST);
}
public Record getRecord() {
Record r = new Record();
r.string = field.getText();
r.isDeleted = isDeleted;
return r;
}
public void setRecord(Record r, int index) {
field.setText(r.string);
this.index = index;
}
}
class RendererAndEditor extends AbstractCellEditor implements
TableCellEditor, TableCellRenderer {
private final CellPanel renderer;
private final CellPanel editor;
public RendererAndEditor(StringTableModel model) {
renderer = new CellPanel(model);
editor = new CellPanel(model);
}
@Override
public Object getCellEditorValue() {
return editor.getRecord();
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
renderer.setRecord((Record)value, row);
return renderer;
}
@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
editor.setRecord((Record)value, row);
return editor;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new StringTableDemo();
}
});
}
}
答案 0 :(得分:4)
这是因为当您点击删除按钮时,CellEditor
没有注意到它必须停止编辑单元格。
一个简单的解决方案是向ActionListener
添加另一个CellEditor
,并在每次点击时调用stopCellEditing()
。这应该有效:
public RendererAndEditor( StringTableModel model )
{
renderer = new CellPanel( model );
editor = new CellPanel( model );
editor.getRemoveBtn().addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
stopCellEditing();
}
});
}