在 JFrame 中更改 JPanel 后如何请求关注 JComponent

How to request focus on JComponent after changing JPanel in JFrame

我有这两个 classes:

class 测试:

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    //frame
    private static JFrame frame = new JFrame() {
        private static final long serialVersionUID = 1L;

        {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(400, 200);
            setLocationRelativeTo(null);
            setLayout(new BorderLayout());

            viewPanel = new JPanel(new BorderLayout());
            add(viewPanel);
        }
    };

    private static JPanel viewPanel;

    //change the panels
    public static void showView(JPanel panel) {
        viewPanel.removeAll();

        viewPanel.add(panel, BorderLayout.CENTER);
        viewPanel.revalidate();
        viewPanel.repaint();
    }

    //main method
    public static void main (String [] args) {

        SwingUtilities.invokeLater(() -> showView(Panels.panel1));

        SwingUtilities.invokeLater(() -> {
            frame.setVisible(true);
        });
    }
}

class 面板:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

//panels
public class Panels {

    //first panel
    static JPanel panel1 = new JPanel() {
        private static final long serialVersionUID = 1L;
        {
            JButton button = new JButton("Click here!");

            add(button);

            button.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    SwingUtilities.invokeLater(() -> Test.showView(panel2));
                }
            });
        }
    };

    //second panel
    static JPanel panel2 = new JPanel() {
        private static final long serialVersionUID = 1L;
        {
            JTextField textField = new JTextField(5);

                add(textField);
        }
    };
}

如您所见,在单击 JButton 后,JFrame 中的 JPanel 发生变化:

但是,在将 panel1 更改为 panel2 之后,我现在如何将焦点设置在 JTextField 上?

我试过将 grabFocus(); 添加到 JTextField,但没有成功,requestFocus(); 也没有成功。

提前致谢!

  1. 无需使用 invokeLater 调用 showView(...)。您的 ActionListener 正在 EDT 上调用,因此这是不必要的代码。
  2. 如果您有 JTextField 的句柄,您可以在使其可见后对其调用 requestFocusInWindow(),并且它应该具有焦点。

例如:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // SwingUtilities.invokeLater(() -> Test.showView(panel2)); // not needed
        Test.showView(panel2);
        Component[] comps = panel2.getComponents();
        if (comps.length > 0) {
            comps[0].requestFocusInWindow();
        }
    }
});

我自己,我会使用 CardLayout 进行交换,不会使用通过 getComponents() 获取组件的笨拙方法,而是使用不那么脆弱的方法调用。

例如:

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyPanelTest extends JPanel {
    private TextFieldPanel textFieldPanel = new TextFieldPanel();
    private CardLayout cardLayout = new CardLayout();

    public MyPanelTest() {
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton(new ButtonAction("Press Me")));        
        setPreferredSize(new Dimension(400, 200));
        setLayout(cardLayout);
        add(buttonPanel, "button panel");
        add(textFieldPanel, TextFieldPanel.NAME);
    }

    private class ButtonAction extends AbstractAction {

        public ButtonAction(String name) {
            super(name);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            cardLayout.show(MyPanelTest.this, TextFieldPanel.NAME);
            textFieldPanel.textFieldRequestFocus();
        }
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("My Panel Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MyPanelTest());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class TextFieldPanel extends JPanel {
    public static final String NAME = "TEXT_FIELD_PANEL";
    private JTextField textField = new JTextField(10);

    public TextFieldPanel() {
        add(textField);
    }

    public void textFieldRequestFocus() {
        textField.requestFocusInWindow();
    }
}