Как поддерживать рендеринг ячейки JTable после редактирования ячейки
Вы, ребята, были настолько круты, что указали мне правильное направление на мой последний вопрос, и у меня есть своего рода продолжение моего первоначального вопроса:
Как установить столбец JTable как String и сортировать как Double?
Поскольку теперь мой столбец цен отформатирован с использованием моего пользовательского средства визуализации ячеек $###,##0,00, я теперь также настроил редактор JTextField для этой ячейки. Редактирование ячейки работает просто отлично, за исключением того, что когда значение обновляется, формат чисел, установленный в моем настраиваемом рендерере, кажется, больше не форматирует ячейку (я теряю $ после того, как редактирование зафиксировано). Разве этот рендер не должен отображать ячейки даже после первоначального отображения данных?
Я попытался использовать следующее без удачи:
((AbstractTableModel) table.getModel()).fireTableDataChanged();
Я надеялся, что это заставит таблицу переоценивать и перерисовывать ячейки, используя пользовательский рендерер для рендеринга новых значений, но, к сожалению, это не сработало...
Я что-то упустил... Очевидно, но что?
1 ответ
Когда ваш редактор завершит, таблица editingStopped()
метод собирает новое значение через getCellEditorValue()
и использует его для setValueAt()
в модели. Модель, в свою очередь, должна fireTableCellUpdated()
, который будет вызывать предписанный рендер. Расширение по умолчанию должно быть достаточно для обработки Number
форматирование. В других случаях может быть удобно использовать экземпляр вашего средства визуализации в качестве компонента редактора; этот пример показывает типичную реализацию.
Приложение: Вот базовый пример использования редактора по умолчанию и реализаций рендерера.
Приложение: Благодаря полезным комментариям @mKorbel я обновил пример выбора текста ячейки для редактирования, как описано в статье @camickr Table Select All Editor.
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://stackru.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();
}
});
}
}