如何在单元格编辑后保持JTable单元格呈现

9

在我的上一个问题中,你们非常棒地指引我方向。这里有一个原问题的补充:

如何将JTable列设置为字符串并排序为Double?

现在,我使用自定义单元格渲染器将价格列格式化为$###,##0.00,并为该单元格设置了JTextField编辑器。编辑单元格的操作正常执行,但是当值更新时,我自定义渲染器中设置的数字格式似乎不再对单元格进行格式化(提交编辑后我失去了$符号)。这个渲染器是否不能在数据的初始显示之后继续渲染单元格?

我尝试使用以下方法,但没有成功:

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

我希望这样做可以强制表格重新验证并重绘单元格,使用自定义渲染器来呈现新值,但不幸的是这并没有起作用... 我是否漏掉了什么... 显然是的,但是是什么呢?
1个回答

11
当你的编辑器结束时,表格的editingStopped()方法通过getCellEditorValue()收集新值,并将其用于模型中的setValueAt()。转而,模型应该fireTableCellUpdated(),这将调用指定的渲染器。扩展默认应足以处理数字格式。在其他情况下,使用您的渲染器实例作为编辑器组件可能是方便的;此示例显示了典型实现。
补充说明:这是一个使用默认编辑器和渲染器实现的基本示例。
补充说明:感谢@mKorbel有益的评论,我已更新示例以选择单元格的文本进行编辑,并遵循@camickr文章Table Select All Editor中描述的方法。 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 https://dev59.com/cWLVa4cB1Zd3GeqPwncO#10067560 */
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();
            }
        });
    }
}

+1 但我之前看到过这个不正确的工作方式,如果您想添加、删除或编辑已存在的值,编辑器会返回0.00 :-),我需要查看一下... - mKorbel
好的观点。对于矩阵输入,编辑器有意在“NumberFormatException”上返回零;“cancelCellEditing()”是一个更通用的替代方案。 - trashgod
这适用于JFormattedTextField或JSpinner作为CellEditor,我确定Rob已经得到了...在那里你必须返回Document,Rob你在哪里 :-) - mKorbel
这个问答揭示了默认编辑器的一些Number处理方式。 - trashgod
我有答案,请看我的帖子。 - mKorbel
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接