代码之家  ›  专栏  ›  技术社区  ›  Konrad Garus

摇摆-如何抓住焦点*现在*?

  •  3
  • Konrad Garus  · 技术社区  · 14 年前

    如何指示Swing组件获取焦点 requestFocus() 似乎不是马上就派出去的。

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

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

    true .

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

    1. 当我在C2栏中键入一个字母时,编辑就开始了。复合编辑器中的文本组件获得焦点。它需要键入启动编辑器的字母。这一点的实现被标注为注释“技巧”。
    2. 文本字段是第三方编辑器,其焦点侦听器会干扰我的代码。这里模拟成 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);
        };
    }
    
    3 回复  |  直到 14 年前
        1
  •  2
  •   Konrad Garus    14 年前

    我想出来了。

    1. 中的事件 AncestorListener processKeyBinding() 是处理同一事件的一部分:“key typed”。
    2. 显然唯一能抓住焦点的方法就是 requestFocus() ,它被添加到由“key typed”触发的当前事件流之后的事件队列中。所以抓住重点执行 FocusListener s将始终稍后执行。

    解决方法是:在 ,不要立即将密钥传递给内部组件。将其放入事件队列,以便在焦点转移和侦听器之后执行。即,包装:

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

    SwingUtilities.invokeLater()

        2
  •  0
  •   JSBÕ±Õ¸Õ£Õ¹    14 年前

    我认为这是不可能的。UI操作本质上是异步的(尽管通常非常快),并且没有办法强制它们进行同步操作。如果确实需要,可以在文本输入的焦点处理程序中触发一个事件,然后在另一个线程中等待该事件。

        3
  •  0
  •   camickr    14 年前

    我不知道如何控制事件的顺序,一般来说,这不是你应该尝试做的事情。

    3.文本字段是具有焦点的第三方编辑器 用我的密码

    也许可以从编辑器中删除FocusListener。也许你可以通过使用

    savedFocusListener.focusGained(FocusEvent);
    

    在AncestorListener代码中,将焦点设置在文本字段上。