java - Swing - 如何*现在*捕获焦点?

标签 java swing

如何指示我的 Swing 组件立即获取焦点? requestFocus() 似乎没有被立即调度。

理想情况下,我希望这样(从 EDT 运行):

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

打印true

下面是 SSCCE。备注/要求:

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

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

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


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() 中的事件是处理同一事件的一部分:“输入键”。
  2. 显然,获取焦点的唯一方法是 requestFocus(),它会在“键入的键”触发的当前事件流之后添加到事件队列中。因此,获取焦点并执行 FocusListener 将始终在稍后执行。

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

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

进入 SwingUtilities.invokeLater()

关于java - Swing - 如何*现在*捕获焦点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3389335/

相关文章:

java - 从另一个类访问对象方法

java - Guice 中的非目标绑定(bind)

java - 了解 Android GC 消息

java - 在处理之前禁用框架

java - 在 Java 中获取 JCombobox 中项目的正确位置

Java Swing - 单用户应用程序到多用户应用程序

java - 如何从 C++ 启动一个 java 进程,并获取它使用的内存?

java - Spring - 事务只读

java - 在 Java Swing 中将用户界面与域分开

Java Jpanel重画/更新问题