带有“,”分隔符而不是“.”的 Jtable 数字编辑器

Jtable Number Editor with "," separator rather than "."

我是法国人,对 Java 并不陌生。 在法语中,双打有“,”分隔符而不是“.”。所以我有一个带有列 class = Double 的 JTable Cell,当我输入例如 2.4 时就可以了。但是当我输入 2,4 时它会阻塞。

我使用了 Locale.setDefault(Locale.FRENCH); 但结果相同:

Number

正如您在下图中所见,我的应用程序以法语语言环境启动: System Locale 有什么方法可以输入 2,4 而不是 2.4 吗?

此致

我建议您使用 AbstractTableModel, then inside the method getValueAt(int row, int col) use NumberFormat 实现自定义数据模型,如下所示:

NumberFormat.getInstance(Locale.FRENCH).format(2.4);

如果您的应用程序仅供法国用户使用,您可以将默认语言环境硬编码为法语。

Locale.setDefault( Locale.FRENCH );

Is there any way to enter 2,4 rather than 2.4 ?

好吧,有几个问题。

  1. 默认渲染器将显示“.”不是“,”。
  2. 默认编辑器将显示“.”,而不是“,”
  3. 当您尝试将值保存到 TableModel 时,默认编辑器无法将“,”识别为 Double 的有效字符

当您离开单元格时,输入的字符串必须转换为 Double。但是,Double.parseDouble(...) 方法无法识别“,”,即使在使用法语语言环境时也是如此。

默认单元格编辑器意识到无法正确转换字符串,因此单元格以红色边框突出显示以指示无效值。

下面的解决方案使用自定义编辑器在内部处理“,”到“.”的转换。在 String 被解析为 Double 之前。它还将转换“。”为“,”,以便该值在编辑器中正确显示。

import java.awt.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class LocaleEditor extends DefaultCellEditor
{
    private Object value;

    public LocaleEditor()
    {
        super( new JTextField() );
        ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
    }

    @Override
    public Object getCellEditorValue()
    {
        return value;
    }

    @Override
    public boolean stopCellEditing()
    {
        try
        {
            String editingValue = (String)super.getCellEditorValue();

            //  Don't allow user to enter "."

            if (editingValue.contains("."))
            {
                JTextField textField = (JTextField)getComponent();
                textField.setBorder(new LineBorder(Color.red));
                return false;
            }

            // Replace local specific character

            int offset = editingValue.lastIndexOf(",");

            if (offset != -1)
            {
                StringBuilder sb = new StringBuilder(editingValue);
                sb.setCharAt(offset, '.');
                editingValue = sb.toString();
            }

            value = Double.parseDouble( editingValue );
        }
        catch(NumberFormatException exception)
        {
            JTextField textField = (JTextField)getComponent();
            textField.setBorder(new LineBorder(Color.red));
            return false;
        }

        return super.stopCellEditing();
    }

    @Override
    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column)
    {
        Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);

        JTextField textField = (JTextField)c;
        textField.setBorder( new LineBorder(Color.BLACK) );

        String text = textField.getText();
        int offset = text.lastIndexOf(".");

        // Display local specific character

        if (offset != -1)
        {
            StringBuilder sb = new StringBuilder(text);
            sb.setCharAt(offset, ',');
            textField.setText( sb.toString() );
        }

        return c;
    }

    private static void createAndShowUI()
    {
        String[] columnNames = {"String", "Double", "Boolean"};

        Object[][] data =
        {
            {"A", new Double(1), Boolean.TRUE },
            {"B", new Double(2.25), Boolean.FALSE},
            {"C", new Double(12.34), Boolean.TRUE },
            {"D", new Double(1234.56), Boolean.FALSE}
        };

        DefaultTableModel model = new DefaultTableModel(data, columnNames)
        {
            //  Returning the Class of each column will allow different
            //  renderers and editors to be used based on Class

            public Class getColumnClass(int column)
            {
                for (int row = 0; row < getRowCount(); row++)
                {
                    Object o = getValueAt(row, column);

                    if (o != null)
                        return o.getClass();
                }

                return Object.class;
            }
        };

        JTable table = new JTable(model);
        table.setRowHeight(20);

        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        //  Use a custom renderer and editor

        NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
        nf.setMinimumFractionDigits(2);
        TableCellRenderer renderer = new NumberRenderer( nf );
        table.setDefaultRenderer(Double.class, renderer);
        TableCellEditor fce = new LocaleEditor();
        table.setDefaultEditor(Double.class, fce);

        JFrame frame = new JFrame("Table Five Character Editor");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( scrollPane );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

以上代码还使用了 Table Format Renderers 中的代码,它使您可以轻松地为给定的语言环境创建自定义渲染器。如果您不想使用渲染器,只需注释掉代码,然后注释掉“。”将显示在 table.

或者,作为解决方法,只需将所有列设置为 String(因此,将接受所有输入),并在 DefaultTableModel->TableModelListener->tableChanged() 根据需要格式化字符串,然后使用 setValueAt().

将其解析为 Double