使用 JTable 单元格编辑器

Posted

技术标签:

【中文标题】使用 JTable 单元格编辑器【英文标题】:using JTable cell editor 【发布时间】:2013-10-31 13:31:45 【问题描述】:

我不确定为什么我为我的 jtable 设置的编辑器没有被调用。我使用了另一个 SO Question 的编辑器示例。

当我编辑我的 jtable 时,它​​只是作为字符串编辑...我希望它只接受数字值。如果我输入任何其他文本可能会出现一些例外情况......但我认为编辑表格时不会在这里调用编辑器。

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.NumberFormatter;

import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;

public class Grow extends JFrame 

private static final Object[][] rowData = "Hello", "World";
private static final Object[] columnNames = "A", "B";

private JTable table;
private DefaultTableModel model;

public Grow() 
     Container c = getContentPane();
     c.setLayout(new BorderLayout());

     model = new DefaultTableModel(rowData, columnNames);
     table = new JTable();
     table.setModel(model);
     c.add(new JScrollPane(table), BorderLayout.CENTER);
     JButton add = new JButton("Add");
     JButton delete = new JButton("Delete");
     c.add(add, BorderLayout.LINE_START);
     add.addActionListener(new ActionListener() 
         public void actionPerformed(ActionEvent ae) 
             model.addRow(rowData[0]);
         
     );

     table.setCellEditor(new NumberCellEditor());

     c.add(delete, BorderLayout.LINE_END);
     delete.addActionListener(new ActionListener() 
         public void actionPerformed(ActionEvent ae) 
             if(table.getSelectedRow()>-1)
                 model.removeRow(table.getSelectedRow());
         
     );

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     pack(); 


class NumberCellEditor extends DefaultCellEditor 
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public NumberCellEditor()
        super(new JFormattedTextField());
    

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

        if (value!=null)
            DecimalFormat numberFormat = new DecimalFormat("#,##0.00;(#,##0.00)");
            editor.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(numberFormat)));
            Number num = (Number) value;  
            String text = numberFormat.format(num);
            editor.setHorizontalAlignment(SwingConstants.RIGHT);
            editor.setText(text);
        
        System.out.println(value);
        return editor;
    

    /*@Override
    public boolean stopCellEditing() 
        try 
            // try to get the value
            //this.getCellEditorValue();
            return super.stopCellEditing();
         catch (Exception ex) 
            return false;
        

    
    */

    @Override
    public Object getCellEditorValue() 
        // get content of textField
        String str = (String) super.getCellEditorValue();
        if (str == null) 
            return null;
        

        if (str.length() == 0) 
            return null;
        

        // try to parse a number
        try 
            ParsePosition pos = new ParsePosition(0);
            Number n = NumberFormat.getInstance().parse(str, pos);
            if (pos.getIndex() != str.length()) 
                throw new ParseException(
                        "parsing incomplete", pos.getIndex());
            

            // return an instance of column class
            return new Float(n.floatValue());

         catch (ParseException pex) 
            throw new RuntimeException(pex);
        
    
    

public static void main(String[] args) 
    Grow g = new Grow();
    g.setLocationRelativeTo(null);
    g.setVisible(true);


【问题讨论】:

请问你的目标是什么 我正在学习为 JTable 创建自定义渲染器和编辑器。我不知道为什么我使用的编辑器对我的示例没有影响。编辑器未正确设置或我错过了要覆盖的内容...? 【参考方案1】:

使用普通的香草JTextFieldDocumentFilter 而不是JFormattedTextField 作为编辑Component

我不能发表评论,附上 JFormattedTextField 的 start_point 和 XxxFormat(重要细节在 Oracle 官方教程中,API How to use FormattedTextFieldNumberFormat 等)

您可以添加 InternationalFormatter 以仅过滤数字

例如

InternationalFormatter formatter = new InternationalFormatter(format);
formatter.setAllowsInvalid(false);
//formatter.setMinimum(0.0);
//formatter.setMaximum(1000.00);

屏幕截图

来自代码

import java.awt.Component;
import java.awt.EventQueue;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

public class EditorAsRendererTableTest 

    public EditorAsRendererTableTest() 
        JTable table = new JTable(3, 2);
        TableColumnModel colModel = table.getColumnModel();
        colModel.getColumn(0).setCellEditor(new MyCellEditor());
        colModel.getColumn(0).setCellRenderer(new MyCellEditor());
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    

    public static void main(String[] args) 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                new EditorAsRendererTableTest();
            
        );
    

    private class MyCellEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer 

        private static final long serialVersionUID = 1L;
        private JFormattedTextField renderer;
        private JFormattedTextField editor;
        private NumberFormat format = DecimalFormat.getInstance();

        public MyCellEditor() 
            format.setMinimumFractionDigits(2);
            format.setMaximumFractionDigits(4);
            format.setRoundingMode(RoundingMode.HALF_UP);
            renderer = new JFormattedTextField(format);
            renderer.setBorder(null);
            editor = new JFormattedTextField(format);
        

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
            renderer.setValue(value);
            return renderer;
        

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
            editor.setValue(value);
            return editor;
        

        @Override
        public boolean stopCellEditing() 
            try 
                editor.commitEdit();
             catch (ParseException e) 
                return false;
            
            return super.stopCellEditing();
        

        @Override
        public Object getCellEditorValue() 
            return editor.getValue();
        
    

【讨论】:

这个例子真的很有用,但是如果想让这个编辑器允许我跟随怎么办: 1.如果我在一个单元格上选择并选择另一个单元格而不输入任何内容它不允许我。如果我点击它,它会迫使我输入一些值。 2.如果我输入的值以数字开头,它会将这些数字转换为忽略字母字符的双精度值。我如何让它只接受数字?【参考方案2】:

我希望它只接受数字值

通常不需要创建自定义编辑器。只需重写 TableModel 的 getColumnClass() 方法以返回存储在模型中的正确数据类,并且表格将使用适当的渲染器和编辑器。

但是,如果您希望编辑器限制小数位数或对数字进行范围检查,那么您可以使用自定义编辑器。

【讨论】:

以上是关于使用 JTable 单元格编辑器的主要内容,如果未能解决你的问题,请参考以下文章

如何使 JTable 单元格不可编辑但应该能够选择和复制当前单元格中的值

当其他单元格值更改时禁用 JTable 单元格可编辑

JTable 无需用户单击即可停止单元格编辑

Java Swing Jtable 单元格不可编辑

仅在选择时设置Jtable单元格可编辑

如何在编辑时选择JTable单元格中的所有文本