删除 JTextField 单元格编辑器的边框在某些情况下不起作用

Removing the border of a JTextField cell editor doesn't work under certain circumstances

由于出现以下问题,此问题是此问题的后续问题:

我在 DefaultCellEditor#getComponent() 上的 JTextArea 已经在 table 上修改其边框时遇到意外行为。边框根本不会 视觉上 改变。

甚至在调用之后:

textField.setBorder(BorderFactory.createCompoundBorder(null, BorderFactory.createEmptyBorder(1, 1, 1, 1)));

紧接着做:

System.out.println(textField.getBorder());

控制台显示 javax.swing.border.CompoundBorder@6aff616,这意味着边框 已在内部更改 。然而,这并没有在视觉上反映出来,我很困惑。

我的测试class:

public class TableWhosebug extends javax.swing.JFrame {

    public TableWhosebug() {
        initComponents();
        prepareTable();
    }

    public void prepareTable() {
        for (int i = 0; i < table.getColumnCount(); i++) {
            Class columnClass = table.getColumnClass(i);
            DefaultCellEditor defaultEditor = (DefaultCellEditor) table.getDefaultEditor(columnClass);
            if (defaultEditor.getComponent() instanceof JTextField) {
                JTextField textField = (JTextField) defaultEditor.getComponent();
                textField.setFont(new Font("Segoe UI", Font.PLAIN, 12));
                textField.setBorder(BorderFactory.createCompoundBorder(null, BorderFactory.createEmptyBorder(1, 1, 1, 1)));
                System.out.println(textField.getBorder());

            }
            defaultEditor.setClickCountToStart(1);
        }
    }

    private void initComponents() {    
        scrPane = new javax.swing.JScrollPane();
        table = new org.jdesktop.swingx.JXTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        table.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null}
            },
            new String [] {
                "First", "Second"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        table.setSelectionBackground(new java.awt.Color(223, 238, 249));
        table.setSelectionForeground(new java.awt.Color(0, 0, 0));
        scrPane.setViewportView(table);

        getContentPane().add(scrPane, java.awt.BorderLayout.CENTER);

        pack();
    }                      

    public static void main(String args[]) {
        try {
            javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
        }

        java.awt.EventQueue.invokeLater(() -> {
            new TableWhosebug().setVisible(true);
        });
    }

    private javax.swing.JScrollPane scrPane;
    private org.jdesktop.swingx.JXTable table;

最后这里有一个令人讨厌的解决方法,它可以工作但不可行:

public void prepareTable() {
    for (int i = 0; i < table.getColumnCount(); i++) {
        DefaultCellEditor defaultEditor = (DefaultCellEditor) table.getDefaultEditor(table.getColumnClass(i));
        if (defaultEditor.getComponent() instanceof JTextField) {
            JTextField textField = new JTextField();
            textField.setFont(new Font("Segoe UI", Font.PLAIN, 12));
            textField.setBorder(BorderFactory.createCompoundBorder(null, BorderFactory.createEmptyBorder(1, 1, 1, 1)));
            defaultEditor = new DefaultCellEditor(textField);
            table.setDefaultEditor(table.getColumnClass(i), defaultEditor);
        }
        defaultEditor.setClickCountToStart(1);
    }
}

终于有了更好用的东西(感谢 Camickr!)

table.addPropertyChangeListener((evt) -> {
    if ("tableCellEditor".equals(evt.getPropertyName())) {
        if (table.isEditing()) {
            JTextField jtextField = (JTextField) ((DefaultCellEditor) table.getCellEditor()).getComponent();
            jtextField.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        }
    }
});
DefaultCellEditor defaultEditor = (DefaultCellEditor) table.getDefaultEditor(columnClass);
System.out.println(defaultEditor.getClass());

将以上语句添加到您的代码中,您将看到默认编辑器是 GenericEditor,它是 JTable 的内部 class。

此编辑器添加了在 JTable 中使用的额外功能。

它所做的其中一件事是管理边界。如果发现错误,编辑器中会显示 "red border"。否则边框设置为默认 "black border".

And finally here is a nasty workaround that makes it work but isn't viable:

您需要使用 DefaultCellEditor 或创建自定义编辑器。

您可以扩展 JTable.GenericEditor class 并覆盖 getTableCellEditor(...) 方法。这是将边框重置为默认黑色边框的方法。

或者您可以将 getCellEditor(...) 方法覆盖到 table 以获取编辑器,然后删除边框。

另一种方法是将 PropertyChangeListener 添加到 table。然后,每当编辑一个单元格时,您都会收到一个事件,这样您就可以获取活动编辑器并删除其边框:

@Override
public void propertyChange(PropertyChangeEvent e)
{
    //  A cell has started/stopped editing

    if ("tableCellEditor".equals(e.getPropertyName()))
    {
        if (table.isEditing())
            // add your code here
    }
}

此外,为什么要使用 CompoundBorder 来创建 EmptyBorder?