英文:
Close JPopupMenu on Keystroke
问题
我正在创建一个工具,用于自动完成Processing IDE的文本,它是Java的定制版本。以下是弹出的弹出菜单类,用于呈现不同的填充选项:
class Entry extends JPopupMenu implements KeyListener{
private JEditTextArea parent;
public Entry(String word, JEditTextArea _parent) {
super();
parent = _parent;
parent.add(this);
parent.addKeyListener(this);
add(word);
}
public void show(int x, int y) {
super.show(parent, x, y);
}
public void keyPressed(KeyEvent key) {
setVisible(false);
setEnabled(false);
}
public void keyReleased(KeyEvent key) {}
public void keyTyped(KeyEvent key) {}
}
父类是一个JEditTextArea,据我所知,它与swing包中的JTextArea大部分功能相同。word参数只是开始输入的单词,作为稍后在代码中查找匹配完成的模式。
问题是,一旦弹出菜单打开,它会阻止进一步输入新字符,你必须通过按ESC键手动关闭它。我尝试将其设置为KeyListener,并在按键时关闭它,但迄今为止没有成功。我还尝试让它在任何按键时打印出简单的消息,但无论我尝试什么,都无法让它对任何形式的键盘输入作出反应。有没有办法让它在接收到按键时关闭?
~Okaghana
英文:
I'm creating a tool to autocomplete Text for the Processing IDE, a customized version of Java. The following class Is the popup-menu that pops up to present the different fill-in possibilities:
class Entry extends JPopupMenu implements KeyListener{
private JEditTextArea parent;
public Entry(String word, JEditTextArea _parent) {
super();
parent = _parent;
parent.add(this);
parent.addKeyListener(this);
add(word);
}
public void show(int x, int y) {
super.show(parent, x, y);
}
public void keyPressed(KeyEvent key) {
setVisible(false);
setEnabled(false);
}
public void keyReleased(KeyEvent key) {}
public void keyTyped(KeyEvent key) {}
}
The parent is a JEditTextArea, that afaik shares most of its functionality with the JTextArea from the swing package. The word parameter is just the word that was started being typed, as a pattern to find a fitting completion later in the code.
The problem is, that as soon as the popup opens it blocks the further input of new characters and you have to manually close it by pressing ESC. I tried to make it a KeyListener and make it close on a keystroke, but had no success so far. I also tries to let it print a simple message on any keystroke, but whatever I try, I can't convince it to react to any form of a key input. Is there a way I can make it close on an incoming keystroke?
~Okaghana
答案1
得分: 1
以下是您提供的代码的翻译部分:
import javax.swing.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
// 创建元素
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("点击我!");
JPopupMenu menu = new JPopupMenu("菜单");
menu.add("A");
menu.add("B");
menu.add("C");
// 在按钮点击时打开菜单
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
menu.show(button, button.getWidth() / 2, button.getHeight() / 2);
}
});
// 在按下CTRL+X时关闭菜单
frame.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
// 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
// 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
menu.setVisible(false);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
// 将所有内容放在一起
panel.add(button);
frame.add(panel);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
这段代码出现问题的原因是键盘监听器被添加到了 JFrame 上。当按钮被按下并且菜单打开时,菜单获得了焦点,因此键盘监听器不起作用。
可以通过添加以下代码来解决这个问题:
// 这是解决的关键
button.setFocusable(false);
menu.setFocusable(false);
如果您不想这样做,而是只想将 KeyListener 添加到 JPopupMenu 上,可以使用以下方法:
// 在按钮点击时打开菜单
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
menu.show(button, button.getWidth() / 2, button.getHeight() / 2);
menu.requestFocus();
}
});
// 在按下CTRL+X时关闭菜单
menu.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
// 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
// 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
menu.setVisible(false);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
关键在于在菜单打开时为其设置焦点(在按钮的 actionlistener 中):
menu.requestFocus();
英文:
I couldn't really work with the class you provided, because there are some classes missing. So I just created this minimal working example, I hope it illustrates your problem:
import javax.swing.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
//Creating elements
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("click me!");
JPopupMenu menu = new JPopupMenu("Menu");
menu.add("A");
menu.add("B");
menu.add("C");
//Open menu on button-click
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
menu.show(button, button.getWidth()/2, button.getHeight()/2);
}
});
//Close menu on CTRL+X
frame.addKeyListener(new KeyListener(){
@Override
public void keyPressed(KeyEvent e) {
//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
menu.setVisible(false);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
//Putting everything together
panel.add(button);
frame.add(panel);
frame.setSize(300,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
This isn't working because the keylistener is added to the JFrame. When the button is pressed and the menu opens, the menu gains focus and therefore the keylistener doesn't work.
This problem can be solved by adding the following lines to the code:
//this is doing the trick
button.setFocusable(false);
menu.setFocusable(false);
If you don't want to do this and want to add the KeyListener only to the JPopupMenu, then you can do this:
//Open menu on button-click
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
menu.show(button, button.getWidth()/2, button.getHeight()/2);
menu.requestFocus();
}
});
//Close menu on CTRL+X
menu.addKeyListener(new KeyListener(){
@Override
public void keyPressed(KeyEvent e) {
//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
menu.setVisible(false);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
The trick here is to set the focus on the menu once it is open (in the actionlistener for the button):
menu.requestFocus();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论