11

JTextFieldユーザーの入力に一致する結果を提案したいと思っているのです。これらの提案をにJList含まれるものに表示していますJPopupMenu

ただし、を介してプログラムでポップアップメニューを開くshow(Component invoker, int x, int y)と、フォーカスはから取得されJTextFieldます。

不思議なことに、setVisible(true)代わりに電話しても、フォーカスは盗まれません。ただし、JPopupMenuはどのパネルにも接続されておらず、ボックスが開いているときにアプリケーションを最小化すると、ウィンドウにペイントされたままになります。

JTextFieldまた、フォーカスをusingにリセットしようとしましたrequestFocus()が、を使用してキャレットの位置を復元する必要があります。後で呼び出すSwingUtilities.invokeLater()と、ユーザーは既存のコンテンツをいじくり回す/上書きする/または他の予測できないことをします。

私が持っているコードは事実上次のとおりです。

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

JPopupMenu誰かが、焦点を合わせながら、プログラムで表示するために降りるのに最適な方法を提案できますJTextFieldか?

4

3 に答える 3

14

技術的な答えは、ポップアップの 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 のソースを調べることを検討してください。

編集

楽しみのために、以下焦点の質問に答えていません :-) 代わりに、並べ替え可能/フィルター可能な 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);
于 2012-04-06T11:38:20.800 に答える
2

とても楽しみです。以下を追加します

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();
于 2012-04-05T17:34:31.327 に答える
1

xswingxの一部であるJXSearchFieldをご覧ください。

于 2012-08-10T12:39:07.327 に答える