如何在单元格编辑后维护JTable单元格渲染

在最后一个问题上,你们真的非常棒,指出了我的正确方向,而且我在这里还有一个原始问题的延伸:

如何设置一个JTable列作为string和sorting为双?

现在我已经使用自定义单元格渲染器将我的价格列格式化为$ ###,## 0.00,现在我也为单元格设置了一个JTextField编辑器。 单元格的编辑工作得很好,除了值更新的时候,在自定义渲染器中设置的数字格式不再像格式化单元格(我放弃$提交之后的编辑提交)。 即使在初始显示数据之后,这个渲染器是否应该渲染单元格?

我曾尝试使用以下运气:

((AbstractTableModel) table.getModel()).fireTableDataChanged(); 

我希望这将迫使表重新validation和重新绘制使用自定义渲染器来渲染新值的单元格,但是这不幸的是没有工作…

我错过了什么…显然,但是什么?

当编辑器结束时,表格的editingStopped()方法通过getCellEditorValue()收集新值并将其用于模型中的setValueAt() 。 该模型反过来应该fireTableCellUpdated() ,它将调用指定的渲染器。 扩展默认值应该足以处理Number格式。 在其他情况下,使用渲染器的实例作为编辑器组件可能会很方便; 这个例子显示了典型的实现。

附录:下面是使用默认编辑器和渲染器实现的基本示例。

附录:感谢来自@mKorbel的有用评论,我更新了示例以select单元格的文本进行编辑,如@ camickr的文章“ 表格全选编辑器”中所述

RenderEditNumber

 package overflow; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.MouseEvent; import java.text.NumberFormat; import java.util.EventObject; import javax.swing.DefaultCellEditor; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.text.JTextComponent; /** @see http://stackoverflow.com/a/10067560/230513 */ public class RenderEditNumber extends JPanel { private NumberFormat nf = NumberFormat.getCurrencyInstance(); public RenderEditNumber() { DefaultTableModel model = new DefaultTableModel( new String[]{"Amount"}, 0) { @Override public Class<?> getColumnClass(int columnIndex) { return Double.class; } }; for (int i = 0; i < 16; i++) { model.addRow(new Object[]{Double.valueOf(i)}); } JTable table = new JTable(model) { @Override // Always selectAll() public boolean editCellAt(int row, int column, EventObject e) { boolean result = super.editCellAt(row, column, e); final Component editor = getEditorComponent(); if (editor == null || !(editor instanceof JTextComponent)) { return result; } if (e instanceof MouseEvent) { EventQueue.invokeLater(new Runnable() { @Override public void run() { ((JTextComponent) editor).selectAll(); } }); } else { ((JTextComponent) editor).selectAll(); } return result; } }; table.setPreferredScrollableViewportSize(new Dimension(123, 123)); table.setDefaultRenderer(Double.class, new CurrencyRenderer(nf)); table.setDefaultEditor(Double.class, new CurrencyEditor(nf)); this.add(new JScrollPane(table)); } private static class CurrencyRenderer extends DefaultTableCellRenderer { private NumberFormat formatter; public CurrencyRenderer(NumberFormat formatter) { this.formatter = formatter; this.setHorizontalAlignment(JLabel.RIGHT); } @Override public void setValue(Object value) { setText((value == null) ? "" : formatter.format(value)); } } private static class CurrencyEditor extends DefaultCellEditor { private NumberFormat formatter; private JTextField textField; public CurrencyEditor(NumberFormat formatter) { super(new JTextField()); this.formatter = formatter; this.textField = (JTextField) this.getComponent(); textField.setHorizontalAlignment(JTextField.RIGHT); textField.setBorder(null); } @Override public Object getCellEditorValue() { try { return new Double(textField.getText()); } catch (NumberFormatException e) { return Double.valueOf(0); } } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { textField.setText((value == null) ? "" : formatter.format((Double) value)); return textField; } } private void display() { JFrame f = new JFrame("RenderEditNumber"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new RenderEditNumber().display(); } }); } }