Swing/ComboBoxSuggestion のバックアップの現在との差分(No.2)
TITLE:JComboBoxで候補一覧を表示
Posted by terai at 2004-12-06
JComboBoxで候補一覧を表示
JComboBoxに入力候補の一覧表示機能*1を追加します。-
category: swing
folder: ComboBoxSuggestion
title: JComboBoxで候補一覧を表示
tags: [JComboBox, KeyListener, JPopupMenu]
author: aterai
pubdate: 2004-12-06T09:47:32+09:00
description: JComboBoxに入力候補の一覧表示機能(補完機能、コードアシスト、コンテンツアシスト)を追加します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2009/01/create-auto-suggest-jcombobox.html lang: en
概要
JComboBox
に入力候補の一覧表示機能(補完機能、コードアシスト、コンテンツアシスト)を追加します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
#screenshot
サンプルコード
#spanend
#spanadd
String[] array = {
#spanend
"aaaa", "aaaabbb", "aaaabbbcc", "aaaabbbccddd",
"abcde", "abefg", "bbb1", "bbb12"};
#spanadd
JComboBox combo = new JComboBox(array);
#spanend
#spanadd
combo.setEditable(true);
#spanend
#spanadd
combo.setSelectedIndex(-1);
#spanend
#spanadd
JTextField field = (JTextField) combo.getEditor().getEditorComponent();
#spanend
#spanadd
field.setText("");
#spanend
#spanadd
field.addKeyListener(new ComboKeyHandler(combo));
#spanend
#spandel
**サンプルコード [#c1c19fbc]
#spanend
#spandel
#code{{
#spanend
#spandel
combo.setEditable(true);
#spanend
#spandel
field = (JTextField) combo.getEditor().getEditorComponent();
#spanend
#spandel
field.addKeyListener(new KeyAdapter() {
#spanend
@Override
public void keyTyped(KeyEvent e) {
keyTypedInCombo(e);
#spanadd
// ...
#spanend
#spanadd
class ComboKeyHandler extends KeyAdapter {
#spanend
private final JComboBox<String> comboBox;
private final List<String> list = new ArrayList<>();
private boolean shouldHide;
#spanadd
#spanend
public ComboKeyHandler(JComboBox<String> combo) {
super();
this.comboBox = combo;
for (int i = 0; i < comboBox.getModel().getSize(); i++) {
list.add(comboBox.getItemAt(i));
}
}
@Override
public void keyPressed(KeyEvent e) {
keyPressedInCombo(e);
#spanadd
#spanend
@Override public void keyTyped(final KeyEvent e) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
String text = ((JTextField) e.getComponent()).getText();
ComboBoxModel<String> m;
if (text.isEmpty()) {
String[] array = list.toArray(new String[list.size()]);
m = new DefaultComboBoxModel<String>(array);
setSuggestionModel(comboBox, m, "");
comboBox.hidePopup();
} else {
m = getSuggestedModel(list, text);
if (m.getSize() == 0 || shouldHide) {
comboBox.hidePopup();
} else {
setSuggestionModel(comboBox, m, text);
comboBox.showPopup();
}
}
}
});
}
//public void keyReleased(KeyEvent e) {
#spandel
});
#spanend
#spandel
View in GitHub: Java, Kotlin#spanend
#spandel
private boolean hide_flag = false;
#spanend
#spandel
private void keyPressedInCombo(KeyEvent ke) {
#spanend
String text = field.getText();
int code = ke.getKeyCode();
if(code==KeyEvent.VK_ENTER) {
if(!model.contains(text)) {
model.addElement(text);
Collections.sort(model);
setModel(getSuggestedModel(model, text), text);
}
hide_flag = true; //combo.hidePopup();
}else if(code==KeyEvent.VK_ESCAPE) {
hide_flag = true; //combo.hidePopup();
}else if(code==KeyEvent.VK_RIGHT) {
for(int i=0;i<model.size();i++) {
String str = model.elementAt(i);
if(str.startsWith(text)) {
combo.setSelectedIndex(-1);
field.setText(str);
return;
@Override public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getComponent();
String text = textField.getText();
shouldHide = false;
switch (e.getKeyCode()) {
case KeyEvent.VK_RIGHT:
for (String s : list) {
if (s.startsWith(text)) {
textField.setText(s);
return;
}
}
break;
case KeyEvent.VK_ENTER:
if (!list.contains(text)) {
list.add(text);
Collections.sort(list);
setSuggestionModel(comboBox, getSuggestedModel(list, text), text);
}
shouldHide = true;
break;
case KeyEvent.VK_ESCAPE:
shouldHide = true;
break;
default:
break;
}
}
#spandel
}
#spanend
#spandel
private void keyTypedInCombo(final KeyEvent ke) {
#spanend
EventQueue.invokeLater(new Runnable() {
public void run() {
String text = field.getText();
if(text.length()==0) {
combo.hidePopup();
setModel(new DefaultComboBoxModel(model), "");
}else{
DefaultComboBoxModel m = getSuggestedModel(model, text);
if(m.getSize()==0 || hide_flag) {
combo.hidePopup();
hide_flag = false;
}else{
setModel(m, text);
combo.showPopup();
}
#spanadd
#spanend
private static void setSuggestionModel(
JComboBox<String> comboBox, ComboBoxModel<String> mdl, String str) {
comboBox.setModel(mdl);
comboBox.setSelectedIndex(-1);
((JTextField) comboBox.getEditor().getEditorComponent()).setText(str);
}
#spanadd
#spanend
private static ComboBoxModel<String> getSuggestedModel(List<String> list, String text) {
DefaultComboBoxModel<String> m = new DefaultComboBoxModel<>();
for (String s : list) {
if (s.startsWith(text)) {
m.addElement(s);
}
}
});
return m;
}
}
解説
解説
上記のサンプルでは、次のキー操作に対応しています。- 上下キー
- ポップアップ表示
- ESCキー
- ポップアップ非表示
- 右キー
- 補完
- リターンキー
- 選択or追加
- 文字入力
- 候補をポップアップ
- Up, Downキー
- ポップアップ表示
- Escキー
- ポップアップ非表示
- Rightキー
- 補完
- Enterキー
- 選択、または追加
- 文字入力
- 候補をポップアップ
- -
-
JComboBox#showPopup()
とJComboBox#hidePopup()
を使って候補のポップアップメニュー表示を制御- 候補を表示するとき
JComboBox#setSelectedIndex(-1)
で項目の選択を一旦クリアしないと動作がおかしくなる場合がある
- 候補を表示するとき
コメント
- 変換途中の日本語も、問題がないともっといいですね。 -- toshi?
- あー、日本語のこと全然考えてなかったです…。 -- terai
- タイトルなどを変更するとしたら AutoCompletion に? -- terai
- 日本語を考えるとKeyReleasedよりKeyTypedのほうがよさそうです -- foggi?
- Enterキーでの追加が出来なくなっていたのを修正しました。 -- terai
- -
-
JComboBox
ではなくSwingSet3
のJHistoryTextField.java のようにJTextField
+JPopupMenu
を使用することも可能だが、画面の下側で候補数が変更された場合のJPopupMenu
の位置更新が面倒 - 以下のように
ArrowButton
を非表示にしてJTextField
風に見せかける方法もある
#spanend
#spanadd
// UIManager.put("ComboBox.squareButton", Boolean.FALSE);
#spanend
#spanadd
JComboBox = new JComboBox(model) {
#spanend
@Override public void updateUI() {
super.updateUI();
setUI(new javax.swing.plaf.basic.BasicComboBoxUI() {
@Override protected JButton createArrowButton() {
JButton button = new JButton() {
@Override public int getWidth() {
return 0;
}
};
button.setBorder(BorderFactory.createEmptyBorder());
button.setVisible(false);
return button;
}
#spanadd
#spanend
@Override public void configureArrowButton() {}
});
for (MouseListener ml: getMouseListeners()) {
removeMouseListener(ml);
}
}
#spanadd
};
#spanend
#spanadd