5

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

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

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

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

4

4 回答 4

2

如果您使用 TextActions,则该操作知道哪个 JTextComponent 具有焦点。我已经修改了我在此处找到的一些代码,以表明即使 TextActions 来自一个 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);
  }
}

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

于 2012-07-02T22:48:26.643 回答
1

我想我已经解决了这个问题,因为当你点击一个菜单项时你会失去焦点,我们只需要等待焦点返回到组件,然后再检查谁有焦点,我使用摇摆计时器完成了这个等待 100ms 然后执行它的方法来检查哪个组件有焦点:

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]);
        }
    }
}
于 2012-07-02T21:48:32.290 回答
1

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

this.rootPane.setFocusable(false);

现在

getFocusOwner()

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

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

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

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

资料来源:个人经历

于 2013-09-08T11:20:43.220 回答
0

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

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

于 2012-07-02T21:20:11.900 回答