Остановка JPopupMenu крадет фокус

у меня естьJTextField для которого я надеюсь предложить результаты, совпадающие с пользовательскими данными. Я отображаю эти предложения в видеJList содержится вJPopupMenu.

However, при открытии всплывающего меню программно черезshow(Component invoker, int x, int y)центр внимания берется изJTextField.

Как ни странно, если я позвонюsetVisible(true) вместо этого фокус не украден; но тогдаJPopupMenu не прикреплен к какой-либо панели, и при сворачивании приложения, когда окно открыто, оно остается окрашенным в окне.

Я также пытался сбросить фокусировку наJTextField с помощьюrequestFocus(), но тогда я должен восстановить позицию каретки, используяSwingUtilities.invokeLater()иinvoke later Одной из сторон является предоставление пользователю небольшого запаса, чтобы возиться с существующим содержимым / перезаписать его / или сделать другие непредсказуемые вещи.

Код, который я получил, эффективно:

<code>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, 0, field.getHeight());
    }
});
</code>

Может кто-нибудь предложить лучший проспект, чтобы спуститься, чтобы показатьJPopupMenu программно, сохраняя при этомJTextField?

Ответы на вопрос(3)

Это выглядит прямо передо мной. Добавьте следующее

field.requestFocus();

после

 menu.add(list);
 menu.show(field, 0, field.getHeight());

Конечно, вам придется написать, когда скрывать всплывающее окно и т. Д. В зависимости от того, что происходит сJTextField.

то есть;

 menu.show(field, field.getX(), field.getY()+field.getHeight());
 menu.setVisible(true);
 field.requestFocus();
 Isaac06 апр. 2012 г., 08:43
Спасибо за Ваш ответ; к сожалению, я уже пробовал этот подход. Это становится более сложным, так как мне нужно восстановить положение каретки, используяSwingUtilities.invokeLater()иinvoke later сторона вещей дает пользователю небольшое право возиться с существующим контентом / перезаписать его / или сделать другие непредсказуемые вещи.
Решение Вопроса

Технический ответ состоит в том, чтобы установить для свойства focusable всплывающего окна значение false:

popup.setFocusable(false);

Подразумевается, что textField должен взять на себя все действия, инициируемые клавиатурой и мышью, которые обычно обрабатываются самим списком, примерно так:

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

Поскольку ваш контекст очень похож на JComboBox, вы можете рассмотреть вопрос об источниках BasicComboBoxUI и BasicComboPopup.

Edit

Просто для удовольствия, следующееis not отвечая на основной вопрос :-) Вместо этого он демонстрирует, как использовать сортируемый / фильтруемый JXList для отображения только тех вариантов в раскрывающемся списке, которые соответствуют набранному тексту (здесь с правилом начала с)

// 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, 0, field.getHeight());
        } 
        model.setRawText(field.getText());
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
    }
};
field.getDocument().addDocumentListener(documentListener);
 27 мар. 2014 г., 10:37
Это мне очень помогло, спасибо!
 01 дек. 2015 г., 10:32
После долгих поисков мне очень помог этот ответ
 Isaac17 апр. 2012 г., 10:58
Отличный ответ ... отлично работает .. спасибо;)

Вы можете взглянуть на JXSearchField, который является частьюxswingx

Ваш ответ на вопрос