Java 我的JDialog有时会收到来自调用应用程序的冗余击键?(提供代码)
我在基于Netbeans RCP 8.2的java(8)中开发了一个复杂的音乐应用程序,我遇到了一个随机出现的奇怪问题 我有一个带有面板的JFrame,其中包含许多jc组件。我使用面板的InputMap/ActionMap来捕获“a”、“b”、…、“g”按键并调用操作 该操作检索键char,然后显示一个JDialog,其中包含一个用于编辑某些文本数据的JTextField 在使用dialog.setVisible(true)显示对话框之前,操作将调用dialog.prepare(char键),以便JDialog可以在显示之前进行初始化。实际上,dialog.prepare(char键)只在jtext字段中追加传递的字符(转换为大写) 这在大多数情况下都有效:例如,我在JFrame中按“c”,然后JDialog在JTextField的末尾显示为“c” 但有时,可能是1/20次,我在JTextfield的末尾得到“Cc” 这就像原始的按键事件(来自JFrame面板中的JComponent,使用InputMap/ActionMap处理)也被JDialog冗余处理 我确认这不是键盘硬件问题。我用Win8在第二台计算机上复制了这个问题(我的是Win10) 我尝试使用KeyListener而不是InputMap/ActionMap,但没有成功 和2/使用java.awt.EventQueue.invokeLater()将密钥字符追加到JTextField中 我创建了一个独立的小应用程序(见下文)来重现问题并促进调试……但这个小应用程序运行良好,我无法重现问题:-(然后我再次与我的真实应用程序代码进行比较,它实际上是相同的代码,只是真实应用程序是一个完整的Netbeans RCP应用程序 那么,Netbeans RCP会影响Swing处理关键事件的方式吗?我觉得很奇怪 我迷路了,任何提示/建议的测试都将不胜感激Java 我的JDialog有时会收到来自调用应用程序的冗余击键?(提供代码),java,multithreading,swing,netbeans-platform,Java,Multithreading,Swing,Netbeans Platform,我在基于Netbeans RCP 8.2的java(8)中开发了一个复杂的音乐应用程序,我遇到了一个随机出现的奇怪问题 我有一个带有面板的JFrame,其中包含许多jc组件。我使用面板的InputMap/ActionMap来捕获“a”、“b”、…、“g”按键并调用操作 该操作检索键char,然后显示一个JDialog,其中包含一个用于编辑某些文本数据的JTextField 在使用dialog.setVisible(true)显示对话框之前,操作将调用dialog.prepare(char键),以
/**
* Try to reproduce double key problem... Failed because this works OK !! :-(
*/
public class PbKeyDouble extends JFrame {
MyDialog dialog;
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
PbKeyDouble o = new PbKeyDouble();
o.setVisible(true);
}
});
}
public PbKeyDouble() {
// GUI INITIALIZATION
// Add a basic panel
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setPreferredSize(new Dimension(300, 200));
JButton button = new JButton("BUTTON");
panel.add(button);
// Button not used, it's only to simulate the real app where a component in the panel has the focus
button.requestFocusInWindow();
// If "A" or "B" key is pressed anywhere, MyAction.actionPerformed() will be called
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("A"), "MyAction");
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("B"), "MyAction");
panel.getActionMap().put("MyAction", new MyAction());
// Prepare JFrame
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
}
private class MyAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("EDT? " + SwingUtilities.isEventDispatchThread()); // Always prints TRUE
if (dialog == null) {
dialog = new MyDialog();
}
// Retrieve the key used to trigger the action
char c = e.getActionCommand().charAt(0);
// Prepare the dialog (insert the char)
dialog.prepare(c);
// Show dialog
dialog.setVisible(true);
}
}
private class MyDialog extends JDialog {
JTextField textfield;
/**
* A simple dialog with just a textfield.
*/
public MyDialog() {
textfield = new JTextField("Hello");
textfield.setColumns(100);
getContentPane().add(textfield);
pack();
setLocationRelativeTo(null);
}
/**
* Append the key (uppercased) at the end of the textfield
*/
public void prepare(char c) {
String text = textfield.getText();
textfield.setText(text + " " + Character.toUpperCase(c));
}
/**
* Overridden to add a global key binding on ESC key to exit the dialog.
* <p>
* This is only to facilitate the test where I need to try many times the process pressing "a" ESC "a" ESC etc.
*
* @return
*/
@Override
protected JRootPane createRootPane() {
JRootPane contentPane = new JRootPane();
contentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("ESCAPE"), "actionCancel");
contentPane.getActionMap().put("actionCancel", new AbstractAction("Cancel") {
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
return contentPane;
}
}
}
/**
*尝试重现双键问题…失败,因为此操作正常!!:-(
*/
公共类PbKeyDouble扩展JFrame{
我的对话;
公共静态void main(字符串[]args){
javax.swing.SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
PbKeyDouble o=新的PbKeyDouble();
o、 setVisible(真);
}
});
}
公共密钥双(){
//GUI初始化
//添加基本面板
JPanel面板=新的JPanel();
getContentPane().add(面板);
面板。设置首选尺寸(新尺寸(300200));
JButton按钮=新JButton(“按钮”);
面板。添加(按钮);
//按钮未使用,它仅用于模拟面板中某个组件具有焦点的真实应用程序
requestFocusInWindow()按钮;
//如果在任意位置按下“A”或“B”键,将调用MyAction.actionPerformed()
panel.getInputMap(JComponent.WHEN_FOCUSED_组件的祖先_).put(KeyStroke.getKeyStroke(“A”),“MyAction”);
panel.getInputMap(JComponent.WHEN_FOCUSED_组件的祖先_).put(KeyStroke.getKeyStroke(“B”),“MyAction”);
panel.getActionMap().put(“MyAction”,newmyAction());
//准备JFrame
setDefaultCloseOperation(关闭时退出);
包装();
setLocationRelativeTo(空);
}
私有类MyAction扩展了AbstractAction{
@凌驾
已执行的公共无效操作(操作事件e){
System.out.println(“EDT?”+SwingUtilities.isEventDispatchThread());//始终打印为TRUE
如果(对话框==null){
dialog=新建MyDialog();
}
//检索用于触发操作的键
char c=e.getActionCommand().charAt(0);
//准备对话框(插入字符)
对话.准备(c);
//显示对话框
对话框.setVisible(true);
}
}
私有类MyDialog扩展JDialog{
JTextField-textfield;
/**
*一个简单的对话框,只有一个文本字段。
*/
公共MyDialog(){
textfield=newjtextfield(“你好”);
textfield.setColumns(100);
getContentPane().add(文本字段);
包装();
setLocationRelativeTo(空);
}
/**
*将键(大写)追加到文本字段的末尾
*/
公共空间准备(字符c){
String text=textfield.getText();
textfield.setText(text+“”+Character.toUpperCase(c));
}
/**
*重写以在ESC键上添加全局键绑定以退出对话框。
*
*这只是为了方便测试,我需要尝试多次按下“a”ESC“a”ESC等。
*
*@返回
*/
@凌驾
受保护的JRootPane createRootPane(){
JRootPane contentPane=新的JRootPane();
contentPane.getInputMap(JComponent.WHEN\u FOCUSED\u组件的祖先\u).put(KeyStroke.getKeyStroke(“ESCAPE”),“actionCancel”);
contentPane.getActionMap().put(“actionCancel”),new AbstractAction(“Cancel”){
@凌驾
已执行的公共无效操作(操作事件e){
setVisible(假);
}
});
返回内容窗格;
}
}
}
但有时,可能是1/20次,我在JTextfield的末尾得到“Cc”
随机问题通常是线程问题的结果
所有Swing组件都应该在事件调度线程(EDT)
上创建和修改
main()方法中的代码没有在EDT上执行,这可能是问题所在
创建GUI的代码应该包装在SwingUtilities.invokeLater(…)
中
查看上的Swing教程以了解更多信息。我发现了这个问题,尽管它对我来说仍然不符合逻辑。欢迎解释 所有Swing组件都应该在事件分派线程(EDT)上创建和修改 是的,在我的代码和sti中就是这样