Swing - 如何抓住焦点*现在*? [英] Swing - how to grab focus *now*?
问题描述
如何指示我的 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:
- 表格使用键盘导航.C2 列有一个复合编辑器.
- 当我在 C2 列中输入一个字母时,编辑开始.复合编辑器内的文本组件获得焦点.它需要输入启动编辑器的字母.这一点的实现标有技巧"的注释.
- 文本字段是一个 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);
};
}
推荐答案
我想通了.
AncestorListener
和processKeyBinding()
中的事件是处理相同事件的一部分:key typed".- 显然,获取焦点的唯一方法是
requestFocus()
,它会在键入的键"触发的当前事件流之后添加到事件队列中.所以获取焦点并执行FocusListener
s 总是会在后面执行.
- Events in
AncestorListener
andprocessKeyBinding()
are a part of handling the same event: "key typed". - 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 executingFocusListener
s 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屋!