Swing中requestFocusInWindow()和grabFocus()的区别

8
我想知道requestFocusInWindow()grabFocus()方法之间的区别。在这个程序中,它们都可以很好地抓取焦点。因此,我不明白它们之间的区别。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Focus extends JFrame
{
JButton jb;

    public Focus()
    {
        createAndShowGUI();
    }

    private void createAndShowGUI()
    {
        setTitle("grabFocus() vs requestFocusInWindow()");
        setLayout(new FlowLayout());
        setSize(400,400);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        jb=new JButton("Open Dialog");
        jb.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae)
            {
                showDialog();
            }
        });

        add(jb);
    }

    private void showDialog()
    {
        JDialog jd=new JDialog();
        jd.setLayout(new GridLayout(2,2));
        jd.setVisible(true);


        JLabel l1=new JLabel("Label 1");
        JLabel l2=new JLabel("Label 2");

        JTextField jt1=new JTextField(20);
        JTextField jt2=new JTextField(20);

        jd.add(l1);
        jd.add(jt1);
        jd.add(l2);
        jd.add(jt2);

        // Both of them are doing the thing
        //jt2.grabFocus();
        jt2.requestFocus();

        jd.pack();
    }

    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable(){
            public void run()
            {
                new Focus();
            }
        });
    }
}
1个回答

20
答案很简单,grabFocus()会抓住焦点,无论顶级祖先是否是聚焦窗口。如果窗口不活动,则被激活以使组件获得焦点。
requestFocusInWindow()仅在其顶层祖先是聚焦窗口时才为其调用的组件获取焦点。
在您的示例中,JDialog是顶级祖先,当单击JButton时,它会自动获取焦点。因此,requestFocusInWindow()grabFocus()没有区别。
我已经重新编写了程序,以更好地理解使用实用方法的区别。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Focus extends JFrame
{
JButton jb;
JTextField jt;

    public Focus()
    {
        createAndShowGUI();
    }

    private void createAndShowGUI()
    {
        setTitle("grabFocus() vs requestFocusInWindow()");
        setLayout(new FlowLayout());
        setSize(400,400);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        jb=new JButton("Open Dialog");
        jb.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae)
            {
                showDialog();
            }
        });

        add(jb);

        jt=new JTextField(20);

        add(jt);
    }

    private void showDialog()
    {
        JDialog jd=new JDialog();
        jd.setLayout(new GridLayout(2,2));
        jd.setVisible(true);


        JLabel l1=new JLabel("Label 1");
        JLabel l2=new JLabel("Label 2");

        JTextField jt1=new JTextField(20);
        JTextField jt2=new JTextField(20);

        jd.add(l1);
        jd.add(jt1);
        jd.add(l2);
        jd.add(jt2);

        jt.requestFocusInWindow();
        //jt.grabFocus();

        jd.pack();
    }

    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable(){
            public void run()
            {
                new Focus();
            }
        });
    }
}

在这里,requestFocusInWindow() 被调用到 jt 上面并且它不起作用(即 jt 没有获取到焦点),因为当单击 JButton 时,JDialog 变成活动窗口并且位于前台,JDialog 中的 JTextField 获取了焦点。

接下来,grabFocus() 起作用。当单击 JButton 时,JDialog 被显示出来,但是不会成为活动窗口。因为在调用 grabFocus() 后,JFrame 立即成为活动顶层祖先并且强制 jt 获取焦点。


9
虽然你在这篇帖子中没有提到具体的事情,但是“grabFocus()不应该被使用”。为了加强这个说法,引用了Java文档中的一句话 - “这个方法是为焦点实现而设计的。客户端代码不应该使用这个方法;相反,应该使用requestFocusInWindow()”-因此扣了1分 :( - nIcE cOw
1
再次创建JDialog(请参见我的注释),不使用父级,也不包装到invokeLater中,然后JDialog是焦点所有者(EDT上的一堆事件),无法将焦点设置到JDialog的子元素,也无法将焦点返回到JFrame。 - mKorbel
@nIcEcOw 但问题只涉及requestFocusInWindow()grabFocus()之间的区别,OP从未问过是否不应使用grabFocus()。这是额外的信息。在StackOverflow上,没有附加信息的答案会被投票否决吗?我只是想知道!;) - JavaTechnical
2
区别在于,程序员应该在应用程序代码中使用其中一个而不是另一个,而不是考虑它们的效果,因为正如Java文档中所说,这部分属于焦点实现。在我看来,当Java文档明确指出在客户端代码中应该使用哪种方法时,发布这个问题本身就是错误的。 - nIcE cOw
答案根本不是一个差异!!好的。你能解释一下客户端为什么不应该使用这个方法吗? - JavaTechnical

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