Java – stop JPopupMenu stealing focus
I have a jtextfield, and I want to suggest that the results match the user's input I show these suggestions in JList included in JPopupMenu
However, when the pop-up menu is opened programmatically through show (component invoker, int x, int y), the focus will be obtained from jtextfield
Strangely, if I call setvisible (true) instead, the focus will not be stolen; But then the JPopupMenu is not attached to any panels, and when the box is opened and the application is minimized, it will remain drawn on the window
I also tried to use requestfocus () to reset the focus to jtextfield, but I had to use swingutilities Invoker () restores the caret position and invokes the latter to give the user a small margin to / overwrite / or do other unpredictable things with the existing content
My code is valid:
JTextField field = new JTextField();
jpopupmenu menu = new jpopupmenu();
field.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
JList list = getAListOfResults();
menu.add(list);
menu.show(field,field.getHeight());
}
});
Can anyone suggest the best way to programmatically display JPopupMenu while retaining attention to jtextfield?
Solution
The technical answer is to set the pop-up focus attribute to false:
popup.setFocusable(false);
This means that textfield must take over all keyboard and mouse triggered operations normally handled by the list itself. Sosmetting is similar to:
final JList list = new JList(Locale.getAvailableLocales());
final jpopupmenu popup = new jpopupmenu();
popup.add(new JScrollPane(list));
popup.setFocusable(false);
final JTextField field = new JTextField(20);
Action down = new AbstractAction("nextElement") {
@Override
public void actionPerformed(ActionEvent e) {
int next = Math.min(list.getSelectedIndex() + 1,list.getModel().getSize() - 1);
list.setSelectedIndex(next);
list.ensureIndexIsVisible(next);
}
};
field.getActionMap().put("nextElement",down);
field.getInputMap().put(
Keystroke.getKeystroke("DOWN"),"nextElement");
Because of your context and JCombo@R_658_2419 @Very similar, you can consider viewing BasicCombo@R_658_2419 @The source of UI and basiccombopopup
edit
Just for fun, the following does not answer the focus question: -) but demonstrates how to use sortable / filterable jxlist to display the options corresponding to typed text in the drop-down list (here to start the rule)
// instantiate a sortable JXList
final JXList list = new JXList(Locale.getAvailableLocales(),true);
list.setSortOrder(SortOrder.ASCENDING);
final jpopupmenu popup = new jpopupmenu();
popup.add(new JScrollPane(list));
popup.setFocusable(false);
final JTextField field = new JTextField(20);
// instantiate a PatternModel to map text --> pattern
final PatternModel model = new PatternModel();
model.setMatchRule(PatternModel.MATCH_RULE_STARTSWITH);
// listener which to update the list's RowFilter on changes to the model's pattern property
Propertychangelistener modelListener = new Propertychangelistener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("pattern".equals(evt.getPropertyName())) {
updateFilter((Pattern) evt.getNewValue());
}
}
private void updateFilter(Pattern newValue) {
RowFilter<Object,Integer> filter = null;
if (newValue != null) {
filter = RowFilters.regexFilter(newValue);
}
list.setRowFilter(filter);
}
};
model.addPropertychangelistener(modelListener);
// DocumentListener to update the model's rawtext property on changes to the field
DocumentListener documentListener = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateAfterDocumentChange();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateAfterDocumentChange();
}
private void updateAfterDocumentChange() {
if (!popup.isVisible()) {
popup.show(field,field.getHeight());
}
model.setRawText(field.getText());
}
@Override
public void changedUpdate(DocumentEvent e) {
}
};
field.getDocument().addDocumentListener(documentListener);
