TITLE:JComboBoxで候補一覧を表示
#navi(../)
RIGHT:Posted by [[terai]] at 2004-12-06
*JComboBoxで候補一覧を表示 [#jc5d9269]
JComboBoxに入力候補の一覧表示機能((補完機能、コードアシスト、コンテンツアシスト))を追加します。

-&jnlp;
-&jar;
-&zip;

#screenshot

**サンプルコード [#c1c19fbc]
#code{{
String[] array = {
    "aaaa", "aaaabbb", "aaaabbbcc", "aaaabbbccddd",
    "abcde", "abefg", "bbb1", "bbb12"};
JComboBox combo = new JComboBox(array);
combo.setEditable(true);
combo.setSelectedIndex(-1);
JTextField field = (JTextField)combo.getEditor().getEditorComponent();
field.setText("");
field.addKeyListener(new ComboKeyHandler(combo));
}}

#code{{
class ComboKeyHandler extends KeyAdapter{
  private final JComboBox comboBox;
  private final Vector<String> list = new Vector<String>();
  public ComboKeyHandler(JComboBox combo) {
    this.comboBox = combo;
    for(int i=0;i<comboBox.getModel().getSize();i++) {
      list.addElement((String)comboBox.getItemAt(i));
    }
  }
  private boolean popupBecomeInvisible = false;
  @Override public void keyTyped(final KeyEvent e) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        String text = ((JTextField)e.getSource()).getText();
        ComboBoxModel m = getSuggestedModel(list, text);
        if(m.getSize()==0 || popupBecomeInvisible) {
          comboBox.hidePopup();
        }else{
          setSuggestionModel(comboBox, m, text);
          comboBox.showPopup();
        }
      }
    });
  }
  @Override public void keyPressed(KeyEvent e) {
    JTextField textField = (JTextField)e.getSource();
    String text = textField.getText();
    popupBecomeInvisible = 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.addElement(text);
          Collections.sort(list);
          setSuggestionModel(comboBox, getSuggestedModel(list, text), text);
        }
        popupBecomeInvisible = true;
        break;
      case KeyEvent.VK_ESCAPE:
        popupBecomeInvisible = true;
        break;
    }
  }
  private static void setSuggestionModel(JComboBox comboBox, ComboBoxModel mdl, String str) {
    comboBox.setModel(mdl);
    comboBox.setSelectedIndex(-1);
    ((JTextField)comboBox.getEditor().getEditorComponent()).setText(str);
  }
  private static ComboBoxModel getSuggestedModel(java.util.List<String> list, String text) {
    DefaultComboBoxModel m = new DefaultComboBoxModel();
    if(text!=null && text.length()!=0) {
      for(String s: list) {
        if(s.startsWith(text)) m.addElement(s);
      }
    }
    return m;
  }
}
}}

**解説 [#se4084d9]
上記のサンプルでは、次のキー操作に対応しています。
-上下キー
--ポップアップ表示
-ESCキー
--ポップアップ非表示
-右キー
--補完
-リターンキー
--選択or追加
-文字入力
--候補をポップアップ

JComboBox#showPopup()とJComboBox#hidePopup()((それぞれ、JComboBox#setPopupVisible メソッドをラップしているだけ))を使って、候補のポップアップメニュー表示を制御します。

JComboBox#setSelectedIndex(-1)で、項目の選択をクリアしないと動作がおかしくなる場合があります。

//**参考リンク
**コメント [#k1139ae6]
- 変換途中の日本語も、問題がないともっといいですね。 -- [[toshi]] &new{2006-04-24 (月) 13:45:06};
- あー、日本語のこと全然考えてなかったです…。 -- [[terai]] &new{2006-04-24 (月) 15:54:00};
- タイトルなどを変更するとしたら AutoCompletion に? -- [[terai]] &new{2007-05-09 (水) 20:14:40};
- 日本語を考えるとKeyReleasedよりKeyTypedのほうがよさそうです -- [[foggi]] &new{2008-05-06 (火) 17:15:39};
-- ご指摘ありがとうございます。keyTyped に変更してみました((ついでにスクリーンショットなども更新))。 -- [[terai]] &new{2008-05-07 (水) 12:23:19};
- Enterキーでの追加が出来なくなっていたのを修正しました。 -- [[terai]] &new{2009-01-22 (木) 16:26:11};

#comment