Swing - 如何抓住焦点*现在*? [英] Swing - how to grab focus *now*?

查看:35
本文介绍了Swing - 如何抓住焦点*现在*?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何指示我的 Swing 组件立即获取焦点?requestFocus() 似乎不会立即发送.

How can I instruct my Swing component to grab focus right now? requestFocus() doesn't seem to be dispatched instantly.

理想情况下,我想要这个(从 EDT 运行):

Ideally, I would like this (ran from EDT):

textInput.requestFocusInWindow();
System.out.println(textInput.hasFocus());

打印true.

下面是 SSCCE.注意事项/要求:

Below is the SSCCE. Notes/requirements:

  1. 表格使用键盘导航.C2 列有一个复合编辑器.
  2. 当我在 C2 列中输入一个字母时,编辑开始.复合编辑器内的文本组件获得焦点.它需要输入启动编辑器的字母.这一点的实现标有技巧"的注释.
  3. 文本字段是一个 3rd 方编辑器,它有一个干扰我的代码的焦点侦听器.这里模拟为selectAll().

目前的调度顺序是:在文本组件中输入字母,然后调度焦点监听器.然后下一个字母被正确发送,因为它是具有焦点的文本字段.

Presently the order of dispatch is: Type letter into text component, then dispatch focus listeners. Then the next letters are dispatched correctly because it's the text field what has focus.

我需要它将焦点设置在文本组件上,调度焦点侦听器,然后将关键事件传递给它.

I need it to set focus on the text component, dispatch focus listeners, and then pass key event to it.

public class JTableIssue extends JFrame {
    public JTableIssue() {
        JTable table = new JTable(new Object[][] {
                { "Apple", "Orange", "Strawberry" },
                { "Pineapple", "Orange", "Zergz" } }, new Object[] { "C1",
                "C2", "C3" });
        table.getColumn("C2").setCellEditor(new MyEditor());
        add(new JScrollPane(table));
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JTableIssue().setVisible(true);
    }
}

class MyEditor extends AbstractCellEditor implements TableCellEditor {
    MyTextField textField = new MyTextField();
    JPanel panel;

    MyEditor() {
        panel = new JPanel(new BorderLayout()){
            // Trick: Pass all key typed to text field
            @Override
            protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                    int condition, boolean pressed) {
                if (ks.getKeyEventType() == KeyEvent.KEY_TYPED) {
                    textField.processKeyBinding(ks, e, condition, pressed);
                }
                return super.processKeyBinding(ks, e, condition, pressed);
            }
        };
        textField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                textField.selectAll();
            }
        });
        panel.add(textField, BorderLayout.CENTER);
        // Trick: Pass focus to text field when editor is added to table
        panel.addAncestorListener(new AncestorListener() {
            public void ancestorRemoved(AncestorEvent event) {
            }

            public void ancestorMoved(AncestorEvent event) {
            }

            public void ancestorAdded(AncestorEvent event) {
                textField.requestFocus();
            }
        });
    }

    public Object getCellEditorValue() {
        return textField.getText();
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int column) {
        textField.setText(value.toString());
        return panel;
    }
}

class MyTextField extends JTextField {
    // Trick: "public"
    @Override
    public boolean processKeyBinding(javax.swing.KeyStroke ks,
            java.awt.event.KeyEvent e, int condition, boolean pressed) {
        return super.processKeyBinding(ks, e, condition, pressed);
    };
}

推荐答案

我想通了.

  1. AncestorListenerprocessKeyBinding() 中的事件是处理相同事件的一部分:key typed".
  2. 显然,获取焦点的唯一方法是 requestFocus(),它会在键入的键"触发的当前事件流之后添加到事件队列中.所以获取焦点并执行 FocusListeners 总是会在后面执行.
  1. Events in AncestorListener and processKeyBinding() are a part of handling the same event: "key typed".
  2. Apparently the only way to grab focus is requestFocus(), which is added to event queue after the current stream of events triggered by "key typed". So grabbing focus and executing FocusListeners will always be executed later.

解决方法是:在processKeyBinding()中,不要立即将key传给内部组件.将其放入事件队列中,以便在焦点转移和侦听器之后执行.即换行:

The solution is: In processKeyBinding(), don't pass the key to the inner component immediately. Enqueue it in event queue, so that it's performed after focus transfer and listeners. That is, wrap:

if (ks.getKeyEventType() == KeyEvent.KEY_TYPED) {
    textField.processKeyBinding(ks, e, condition, pressed);
}

进入SwingUtilities.invokeLater().

这篇关于Swing - 如何抓住焦点*现在*?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆