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
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();