java - 在 JFrame 中更改 JPanel 后如何请求对 JComponent 的关注

标签 java swing jpanel focus jtextfield

我有这两门课:

类测试:

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);
        });
    }
}

类面板:

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 后,JPanel 在 JFrame 内发生变化:How can I change the JPanel from another Class?

但是,在将 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();
    }
}

关于java - 在 JFrame 中更改 JPanel 后如何请求对 JComponent 的关注,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48155677/

相关文章:

java - 使用paintComponent()和高CPU使用率

java - 在 JTable 中禁用单列拖动

java - 如何扩展 JTabbedPane 以始终具有 "Add Tab"选项卡?

java - 有没有办法缩短这段重复的代码? (添加 JPanel 组件)

java - '_id'可以与Java UUID映射吗?

java - POST 文件(作为二进制流)使用 java.net.HttpURLConnection 作为参数 file=<file binary stream>

java - SWIG,我可以为从 Java 传递到 C 的 char** 赋值吗

java - 游戏框架 2.2.6。默认缓存过期

Java:帮助使用 KeyAdapter

java - 动态创建 JPanel