我有一个错误潜伏在哪里,在弹出包含文本字段的JOptionPane
之后,焦点偶尔不会出现在我想要的文本字段上。
我最终把它归结为一个合理的例子:
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Component;
public class FocusIssueTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// The real thing has many more components in there,
// but I removed them for the demo.
MyInputPane myInputPane = new MyInputPane();
myInputPane.showDialog(null);
}
});
}
public static class MyInputPane extends JPanel {
private final JTextField textField;
protected MyInputPane() {
textField = new JTextField();
textField.selectAll();
textField.setColumns(30);
setLayout(new BorderLayout());
add(textField, BorderLayout.CENTER);
}
public boolean showDialog(Component parentComponent) {
final JOptionPane optionPane = new JOptionPane(
this, JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
JDialog dialog = optionPane.createDialog(
parentComponent, "Select a Thing");
/* Attempted solution #1 - wait until the window is active
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent event) {
textField.requestFocusInWindow();
}
});
*/
/* Attempted solution #2 - camickr's RequestFocusListener
textField.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
JComponent component = event.getComponent();
component.requestFocusInWindow();
component.removeAncestorListener(this);
}
@Override
public void ancestorRemoved(AncestorEvent event) {
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
});
*/
/* Attempted solution #3 - HierarchyListener
textField.addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent event) {
Component component = event.getComponent();
if ((HierarchyEvent.SHOWING_CHANGED &
event.getChangeFlags()) != 0 &&
component.isShowing()) {
component.requestFocusInWindow();
component.removeHierarchyListener(this);
}
}
});
*/
// Attempted solution #4 - appears to work but can't be
// right, because eww.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
textField.requestFocusInWindow();
}
});
}
});
}
});
dialog.setVisible(true);
Object selectedValue = optionPane.getValue();
return selectedValue instanceof Integer &&
(int) selectedValue == 0;
}
}
}
尝试的解决方案#1到#3都无法将焦点放在文本字段中。尝试过的解决方案#4有效,但必须使用三级嵌套SwingUtilities.invokeLater
调用,这可能是正确的方法。
那么是正确的方式?
我注意到JOptionPane.showInputDialog
'文本字段 获得焦点,所以显然有一种方法可以做到。
答案 0 :(得分:2)
我不知道规范的解决方案,但您可以尝试在窗口侦听器中的事件线程上进行一次调用。例如,
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent event) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textField.requestFocusInWindow();
}
});
}
});
其他可能" kludges"包括使用简短的单次运行Swing计时器。
答案 1 :(得分:2)
您是否考虑过直接子类化/初始化JDialog而不是使用JOptionPane?
java之所以没有" setFocusInWindow"是因为在某些平台上不可能直接"设置"焦点(尽可能多地请求它。)
对我而言,似乎是对" setVisible()"的调用。将事件放在EDT上,使窗口可见,这反过来又将焦点从文本字段中移开。