【问题标题】:JFrame's getFocusOwner() not being helpfulJFrame 的 getFocusOwner() 没有帮助
【发布时间】:2012-07-03 07:22:51
【问题描述】:

我正在使用 Swing 程序并且遇到了一些麻烦。该程序有两个窗口(都是 JFrames)。主窗口很好,应该与这个问题无关。

我遇到问题的窗口包含一个带有 JPanel 的 JScrollPane,并且有一个 JMenuBar。 JPanel 上有一堆 JTextComponents(一些 JTextFields,一些 JTextAreas)。

我想做的是让一个附加到 JMenuItem 的 ActionListener 找到具有焦点的 JTextComponent。

我在focused component referenceHow to find out which object currently has focus 看到过之前的帖子。我的问题是调用特定窗口的getFocusOwner() 方法只会返回JFrame 的JRootPane,这完全没有帮助。根据它们的isFocusable() 方法,所讨论的 JScrollPane 和 JPanel 都是可聚焦的。即使我在单击菜单项之前实际将文本输入到其中一个 JTextComponents 中,也会发生这种情况。当我打开菜单和所有内容时,光标仍然在文本字段中闪烁。对于它的价值,getMostRecentFocusOwner() 也只是返回 JRootPane。

【问题讨论】:

  • 不知道你的代码有什么问题,getFocusOwner() 和 getMostRecentFocusOwner() 方法都应该返回相同的组件,没错,JMenuItem 使用来自 ButtonModel 的事件,来自 ActiionListener 的事件正确地返回焦点到Container,为了获得更好的帮助,请尽快发布 SSCCE 证明您对 JMenu(Xxx) 和 ActionListener 的问题,JMenu 和 JMenuItems 也有自己的 Listeners
  • 您确定需要此信息吗?通常有不止一种方法可以解决一个整体问题。
  • 我想我已经得到了你想要的工作,请看我修改后的帖子
  • “程序有两个窗口(都是JFrames)。”The Use of Multiple JFrames, Good/Bad Practice?
  • 这是一个有趣的观点,也许 JDialog 可以很好地满足我的目的。然而,这个应用程序的特殊设计方式,基本上是抽象的和易于扩展的,由经验丰富的程序员但不一定使用 Java 或 Swing 的人设计,我相信证明这种选择是正确的。 (例如,我可以预见从其他纯命令行会话启动其中一个子窗口的能力。)

标签: java swing


【解决方案1】:

如果您使用 TextActions,则该操作知道哪个 JTextComponent 具有焦点。我已经修改了一些我发现 here 的代码,以表明即使 TextAction 来自一个 JTextArea,它们仍然会自动处理所有具有焦点的文本组件:

import java.awt.GridLayout;
import javax.swing.*;

public class TextActionExample {
  public static void main(String[] args) {

    // Create a text area.
    JTextArea ta = new JTextArea(15, 30);
    ta.setLineWrap(true);

    // Add all actions to the menu (split into two menus to make it more
    // usable).
    Action[] actions = ta.getActions();
    JMenuBar menubar = new JMenuBar();
    JMenu actionmenu = new JMenu("Actions");
    menubar.add(actionmenu);

    JMenu firstHalf = new JMenu("1st Half");
    JMenu secondHalf = new JMenu("2nd Half");
    actionmenu.add(firstHalf);
    actionmenu.add(secondHalf);

    int mid = actions.length / 2;
    for (int i = 0; i < mid; i++) {
      firstHalf.add(actions[i]);
    }
    for (int i = mid; i < actions.length; i++) {
      secondHalf.add(actions[i]);
    }

    JTextField textField = new JTextField(20);
    JPanel textFieldPanel = new JPanel();
    textFieldPanel.add(textField);

    JPanel mainPanel = new JPanel(new GridLayout(1, 0, 5, 5));
    mainPanel.add(new JScrollPane(ta));
    mainPanel.add(new JScrollPane(new JTextArea(15, 30)));
    mainPanel.add(textFieldPanel);


    // Show it . . .
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(mainPanel);
    f.setJMenuBar(menubar);
    f.pack();
    f.setVisible(true);
  }
}

这是非常有趣的东西,我必须了解更多。

【讨论】:

  • 大卫所说的(如果可以的话,我会 +1)。希望在某个时候,我会将他的解决方案升级为这种风格的东西——它在各个方面看起来都非常干净。
【解决方案2】:

我想我已经解决了这个问题,因为当你点击一个菜单项时你失去了焦点,我们只需要等待焦点返回到组件之前我们检查谁有焦点,我已经做到了这一点一个等待 100 毫秒然后执行它的方法来检查哪个组件具有焦点的摆动计时器:

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.TimerTask;
import javax.swing.*;

public class JavaApplication180 extends JFrame {

    private JTextField[] JTextFields;
    private JMenuBar menuBar;
    private JMenu menu;
    private JMenuItem item;

    public JavaApplication180() {
        initComponents();

        createAndShowUI();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new JavaApplication180();
            }
        });
    }

    private void createAndShowUI() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridLayout(2, 2, 10, 10));
        setJMenuBar(menuBar);
        addComponentsToPane();

        pack();
        setVisible(true);
    }

    private void initComponents() {
        JTextFields = new JTextField[4];

        menuBar = new JMenuBar();
        item = new JMenuItem("Who has focus?");
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                TimerTask tt = new TimerTask() {

                    @Override
                    public void run() {
                        JOptionPane.showMessageDialog(null, getMostRecentFocusOwner().getName());
                    }
                };
                new java.util.Timer().schedule(tt, 100);
            }
        });

        menu = new JMenu("File");
        menu.add(item);
        menuBar.add(menu);
    }

    private void addComponentsToPane() {
        for (int i = 0; i < JTextFields.length; i++) {
            JTextFields[i] = new JTextField();
            JTextFields[i].setText(String.valueOf(i));
            JTextFields[i].setName(String.valueOf(i));
            getContentPane().add(JTextFields[i]);
        }
    }
}

【讨论】:

  • 不,这行不通,因为他希望从 JMenuItem 中获取此信息,而不是从不可聚焦(现在这是一个杂项)JButton。
  • 嗯,是的,仍在修补源代码,但似乎不可能为 JMenuItem 添加它,因为它们不能成为不可聚焦的!
  • 不,不是不可能,但我还不知道解决方案。我认为 kleopatra 对 TextActions 的想法是正确的。
  • @Hovercraft Full Of Eels,似乎可以通过一些工作来解决:)
  • 非常感谢,大卫!我最终以非常相似的方式使用了一个 jankier 但响应速度稍快的解决方案。 (这个程序显然之前没有产生足够多的随机实用程序线程......)
【解决方案3】:

我可能为时已晚,但我刚刚在我的 JFrame 构造函数中执行了以下操作。

this.rootPane.setFocusable(false);

现在

getFocusOwner()

将返回当前的 JTextComponent 而不是 rootPane。 然后我在附加到我的 JMenuItem 的 ActionListener 中使用此代码来选择其中的文本。

if (getFocusOwner() instanceof JTextField)
{
    ((JTextField) getMostRecentFocusOwner()).selectAll();
}

需要注意的是,如果你有 JScrollPane 等,你可能必须在 rootPane 和文本字段之间的所有组件上使用 setFocusable(false)。

希望这可以帮助遇到同样问题的其他人!

来源:个人经历

【讨论】:

    【解决方案4】:

    当我需要这个时,我写了一个焦点监听器。我有一个带有两列 JTextField 的 JPanel,焦点侦听器跟踪用户最后使用的列。我使用户能够通过单击按钮在最后一个焦点列中输入一些文本。您将只对所有文本字段使用 FocusListener 的一个实例,并有一个引用最近关注的组件的字段。然后,您的菜单操作可以查询该字段以确定要使用的文本字段。

    http://docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html

    【讨论】:

      猜你喜欢
      • 2011-11-12
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 2012-02-20
      • 2015-01-26
      • 1970-01-01
      相关资源
      最近更新 更多