禁用 JButton 时 JFrame 焦点问题

Issue with JFrame focus when disabling JButton

我的 Java 应用程序遇到了一个非常奇怪的问题。我正在使用 Netbeans,所以我有一个带有主面板的 frameview,其中有一些按钮可以选择串行端口并连接到它。它还有一个菜单栏可以打开一堆不同的框架。

问题是:有时当我打开另一个框架时,如果我点击回到我的主面板,焦点会立即回到打开的框架(而不是我刚刚点击的面板)。当它执行此操作时,它还会突出显示此打开的框架中的 JComponents,基本上是通过在主面板上每次单击和释放鼠标来切换它们。所以总而言之,焦点不断从我点击的框架跳开。我正在使用 autoRequestFocus。

我缩小了范围,发现这只发生在我点击连接到串行端口按钮后打开的第一帧。所以我会: 启动应用程序->连接到串口->从菜单栏打开不同的框架->点击回到主面板,但我的焦点立即回到打开的框架

所以我意识到它必须是我连接到串行端口 JToggleButton 方法中的东西。最后,我发现如果我注释掉一行代码,问题就解决了。那一行是:

refreshPortsButton.setEnabled(false);

refreshPortsButton 填充可用串口列表,我不希望人们在连接后这样做。

我有一个变通方法,将按钮的可见性设置为 false,但我宁愿将按钮显示为灰色,这种行为对我来说太奇怪了,我真的很想弄明白。启用按钮的状态怎么可能搞乱事情的焦点。 这是一个SSCCE,我尽量简化了它,对不起长initComponents

FocusSSCCEApp.java

package focussscce;

import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;

public class FocusSSCCEApp extends SingleFrameApplication {

    @Override protected void startup() {
        show(new FocusSSCCEView(this));
    }


    @Override protected void configureWindow(java.awt.Window root) {
    }


    public static FocusSSCCEApp getApplication() {
        return Application.getInstance(FocusSSCCEApp.class);
    }


    public static void main(String[] args) {
        launch(FocusSSCCEApp.class, args);
    }
}

FocusSSCCEView.java

package focussscce;

import java.awt.Color;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import java.awt.event.ItemEvent;

/**
 * The application's main frame.
 */
public class FocusSSCCEView extends FrameView {

    public final static Color DARK_GREEN = new Color(0, 150, 0);

    public FocusSSCCEView(SingleFrameApplication app) {
        super(app);

        initComponents();
        this.getFrame().setResizable(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        mainPanel = new javax.swing.JPanel();
        refreshPortsButton = new javax.swing.JButton();
        connectToggleButton = new javax.swing.JToggleButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu prefMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem prefMenuItem = new javax.swing.JMenuItem();
        preferencesFrame = new javax.swing.JFrame();
        textField1 = new javax.swing.JTextField();
        textField2 = new javax.swing.JTextField();

        mainPanel.setMaximumSize(new java.awt.Dimension(150, 50));
        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setPreferredSize(new java.awt.Dimension(493, 50));
        mainPanel.setLayout(new java.awt.GridLayout());

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(focussscce.FocusSSCCEApp.class).getContext().getResourceMap(FocusSSCCEView.class);
        refreshPortsButton.setText(resourceMap.getString("refreshPortsButton.text")); // NOI18N
        refreshPortsButton.setName("refreshPortsButton"); // NOI18N
        refreshPortsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshPortsButtonActionPerformed(evt);
            }
        });
        mainPanel.add(refreshPortsButton);

        connectToggleButton.setText(resourceMap.getString("connectToggleButton.text")); // NOI18N
        connectToggleButton.setFocusPainted(false);
        connectToggleButton.setFocusable(false);
        connectToggleButton.setName("connectToggleButton"); // NOI18N
        connectToggleButton.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                connectToggleButtonItemStateChanged(evt);
            }
        });
        mainPanel.add(connectToggleButton);

        menuBar.setName("menuBar"); // NOI18N

        prefMenu.setText(resourceMap.getString("prefMenu.text")); // NOI18N
        prefMenu.setName("prefMenu"); // NOI18N

        prefMenuItem.setText(resourceMap.getString("prefMenuItem.text")); // NOI18N
        prefMenuItem.setName("prefMenuItem"); // NOI18N
        prefMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                prefMenuItemActionPerformed(evt);
            }
        });
        prefMenu.add(prefMenuItem);

        menuBar.add(prefMenu);

        preferencesFrame.setTitle(resourceMap.getString("preferencesFrame.title")); // NOI18N
        preferencesFrame.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        preferencesFrame.setMinimumSize(new java.awt.Dimension(100, 70));
        preferencesFrame.setName("preferencesFrame"); // NOI18N
        preferencesFrame.setResizable(false);
        preferencesFrame.getContentPane().setLayout(new java.awt.GridLayout());

        textField1.setName("textField1"); // NOI18N
        textField1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                textField1MouseEntered(evt);
            }
        });
        preferencesFrame.getContentPane().add(textField1);

        textField2.setName("textField2"); // NOI18N
        textField2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                textField2MouseEntered(evt);
            }
        });
        preferencesFrame.getContentPane().add(textField2);

        setComponent(mainPanel);
        setMenuBar(menuBar);
    }// </editor-fold>                        

    private void refreshPortsButtonActionPerformed(java.awt.event.ActionEvent evt) {                                                   
        //populateCommPort();
    }                                                  

    private void connectToggleButtonItemStateChanged(java.awt.event.ItemEvent evt) {                                                     
        if (evt.getStateChange() == ItemEvent.SELECTED) {

            //connect();
            connectToggleButton.setText("Disconnect");
            connectToggleButton.setForeground(DARK_GREEN);
            refreshPortsButton.setEnabled(false); //Disabling this remedies the problem
        } else if (evt.getStateChange() == ItemEvent.DESELECTED) {
            //disconnect();
            refreshPortsButton.setEnabled(true);
            connectToggleButton.setText("Connect");
            connectToggleButton.setForeground(Color.BLACK);
        }
    }                                                    

    private void textField1MouseEntered(java.awt.event.MouseEvent evt) {                                        
        textField1.setToolTipText( textField1.getText() );
    }                                       

    private void prefMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                             
        preferencesFrame.setVisible( true );
        preferencesFrame.requestFocusInWindow();
        preferencesFrame.pack();
    }                                            

    private void textField2MouseEntered(java.awt.event.MouseEvent evt) {                                        
        textField2.setToolTipText( textField2.getText() );
    }                                       

    // Variables declaration - do not modify                     
    private javax.swing.JToggleButton connectToggleButton;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JFrame preferencesFrame;
    private javax.swing.JButton refreshPortsButton;
    private javax.swing.JTextField textField1;
    private javax.swing.JTextField textField2;
    // End of variables declaration                   
}

我相信当你的框架上有一个可对焦的组件时,java 会在其上绘制对焦矩形。

我添加了另一个按钮,一旦 refreshPortsButton 按钮被禁用,焦点会自动跳到下一个可聚焦的按钮。

我禁用了 refreshPortsButton 上的 focusPaint,它工作正常。您可以在启用按钮后重新启用它。

private void bConnectActionPerformed(ActionEvent evt) {                                   
    refresh.setEnabled(!refresh.isEnabled());
    refresh.setFocusPainted(refresh.isEnabled());
    if (refresh.isEnabled()) {
        refresh.requestFocus();
    }
    b2.setEnabled(!b2.isEnabled());
    b2.setFocusPainted(b2.isEnabled());
}