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