与后端数据结构同步的JTable设计

7

我有一个JTable,它使用表格模型从数据结构中加载。数据结构的格式为NavigableMap<Float,NavigableMap<Float,Boolean>>。一个示例数据如下:

Table Format:
 Range     f1,v1   f2,v2    f3,v3   f4,v4
12.1-30.2 30,true 32,false 45,true 50,false
30.2-45.6 30,true 32.4,true 45,true 50.1,true

上述数据格式在DS中表示为:
DS Format:
Key  Value
12.1 <<30,true>,<32,false>,<45,true>,<50,false>>
30.2 <<30,true>,<32.4,true>,<45,true>,<50.1,true>>
45.6 null

我已经使用表格模型将上述数据表示为JTable。一旦数据从DS加载到表格中,我需要允许用户进行编辑。这就是我的问题所在。我的疑问是是否应该保持数据结构与表格中的更改同步,还是在用户完成编辑后从表格中重新创建DS,然后用旧的DS替换它。
此外,我需要验证数据(例如,对于上面的例子 - 假设用户想要编辑值30.1。他只能输入12.1和45.6之间的值。由于表格中的数据是字符串(一旦加载),因此我打算使用正则表达式和键盘监听器,并消耗所有不符合正则表达式和不在范围内的用户按键。我不确定这是否是一个好主意或有什么影响。我希望能得到一些建议。
1个回答

14

当用户完成表格编辑后,我会重新创建您的DS。

您可以始终创建自定义编辑器来显示弹出对话框,在其中为范围的每个值都有两个单独的文本字段。然后,您可以在指定的范围内将每个字段作为双精度值进行编辑,并在保存到模型之前重新创建格式化字符串。这是一个旧示例,可以帮助您入门:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

/*
 * The editor button that brings up the dialog.
 */
//public class TablePopupEditor extends AbstractCellEditor
public class TablePopupEditor extends DefaultCellEditor
    implements TableCellEditor
{
    private PopupDialog popup;
    private String currentText = "";
    private JButton editorComponent;

    public TablePopupEditor()
    {
        super(new JTextField());

        setClickCountToStart(2);

        //  Use a JButton as the editor component

        editorComponent = new JButton();
        editorComponent.setBackground(Color.white);
        editorComponent.setBorderPainted(false);
        editorComponent.setContentAreaFilled( false );

        //  Set up the dialog where we do the actual editing

        popup = new PopupDialog();
    }

    public Object getCellEditorValue()
    {
        return currentText;
    }

    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column)
    {

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                System.out.println("run");
                popup.setText( currentText );
//              popup.setLocationRelativeTo( editorComponent );
                Point p = editorComponent.getLocationOnScreen();
                popup.setLocation(p.x, p.y + editorComponent.getSize().height);
                popup.show();
                fireEditingStopped();
            }
        });

        currentText = value.toString();
        editorComponent.setText( currentText );
        return editorComponent;
    }

    /*
    *   Simple dialog containing the actual editing component
    */
    class PopupDialog extends JDialog implements ActionListener
    {
        private JTextArea textArea;

        public PopupDialog()
        {
            super((Frame)null, "Change Description", true);

            textArea = new JTextArea(5, 20);
            textArea.setLineWrap( true );
            textArea.setWrapStyleWord( true );
            KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
            textArea.getInputMap().put(keyStroke, "none");
            JScrollPane scrollPane = new JScrollPane( textArea );
            getContentPane().add( scrollPane );

            JButton cancel = new JButton("Cancel");
            cancel.addActionListener( this );
            JButton ok = new JButton("Ok");
            ok.setPreferredSize( cancel.getPreferredSize() );
            ok.addActionListener( this );

            JPanel buttons = new JPanel();
            buttons.add( ok );
            buttons.add( cancel );
            getContentPane().add(buttons, BorderLayout.SOUTH);
            pack();

            getRootPane().setDefaultButton( ok );
        }

        public void setText(String text)
        {
            textArea.setText( text );
        }

        /*
        *   Save the changed text before hiding the popup
        */
        public void actionPerformed(ActionEvent e)
        {
            if ("Ok".equals( e.getActionCommand() ) )
            {
                currentText = textArea.getText();
            }

            textArea.requestFocusInWindow();
            setVisible( false );
        }
    }

    public static void main(String[] args)
    {
        String[] columnNames = {"Item", "Description"};
        Object[][] data =
        {
            {"Item 1", "Description of Item 1"},
            {"Item 2", "Description of Item 2"},
            {"Item 3", "Description of Item 3"}
        };

        JTable table = new JTable(data, columnNames);
        table.getColumnModel().getColumn(1).setPreferredWidth(300);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);

        // Use the popup editor on the second column

        TablePopupEditor popupEditor = new TablePopupEditor();
        table.getColumnModel().getColumn(1).setCellEditor( popupEditor );

        JFrame frame = new JFrame("Popup Editor Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add( scrollPane );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

注意:上面的代码显示为多行,但是在编辑器中不允许输入回车,因为回车被捕获为退出信号。因此,如果您的数据也需要多行,请在PopupDialog构造函数中使用“keyStroke”注释掉这两行。在这种情况下,只有在单击OK按钮时,弹出窗口才会退出。 - R71
这是一个很好的例子!但我们大多数时候都会遇到丢失第一个按键的问题,并在stackoverflow上发布了一个新的问题:https://stackoverflow.com/questions/50256757/jtextarea-dialog-as-jtable-celleditor-misses-first-typed-character - bobndrew

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