一、背景介绍

在许多Windows应用程序里面,最常见的是IE的地址栏,当我们在ComboBox的文本框内容时,它的下拉列表中自动列出最匹配的项目,并且将最匹配的项目显示在输入框中。  
在Java中有个JComboBox类,它可以实现下拉选择或者输入选择。但是它本身没有提供自动查找和完成功能。我们现在就来   “改装”这个类,使它具有自动查找和完成功能。

二、思路

1.先继承一个JComboBox类,将其setEditable为true.   这样的话,用户才可以在combobox上输入文字。  
2.我们知道combobox的输入框是一个JTextField,   可以通过comboBox.getEditor().getEditorComponent()取得这个文本框。  
3.为这个文本框加上一个KeyListener.  
4.当用户在文本框中按键时,会触发keyPressed和keyReleased事件,我们在keyPressed事件中实现点击除Enter按键之外的键清楚text内容,在这个keyReleased事件里写主要的实现自动查找和完成的代码。

三、实现

/**
 * Aug 23, 2016
 * 
 * @author HHL 下拉列表输入自动填充类
 * 
 */
public class JAutoCompleteComboBox extends JComboBox {

	private AutoCompleter completer;

	public JAutoCompleteComboBox() {
		super();
		addCompleter();
	}

	public JAutoCompleteComboBox(ComboBoxModel cm) {
		super(cm);
		addCompleter();
	}

	public JAutoCompleteComboBox(FreightSwing fs, ComboBoxModel cm,
			ItemListener itemListener) {
		super(cm);
		addCompleter(fs, itemListener);
	}

	private void addCompleter(FreightSwing fs, ItemListener itemListener) {
		setEditable(true);
		completer = new AutoCompleter(this, itemListener, fs);

	}

	public JAutoCompleteComboBox(Object[] items) {
		super(items);
		addCompleter();
	}

	public JAutoCompleteComboBox(List v) {
		super((Vector) v);
		addCompleter();
	}

	private void addCompleter() {
		setEditable(true);
		completer = new AutoCompleter(this);
	}

	public void autoComplete(String str) {
		this.completer.autoComplete(str, str.length());
	}

	public String getText() {
		return ((JTextField) getEditor().getEditorComponent()).getText();
	}

	public void setText(String text) {
		((JTextField) getEditor().getEditorComponent()).setText(text);
	}

	public boolean containsItem(String itemString) {
		for (int i = 0; i < this.getModel().getSize(); i++) {
			String _item = " " + this.getModel().getElementAt(i);
			if (_item.equals(itemString))
				return true;
		}
		return false;
	}

	// public static void main(String[] args) {
	// JFrame frame = new JFrame();
	// Object[] items = new Object[] { "abc ", "aab ", "aba ", "hpp ", "pp ",
	// "hlp " };
	// DefaultComboBoxModel model = new DefaultComboBoxModel();
	// JComboBox cmb = new JAutoCompleteComboBox(model);
	// model.addElement("abc ");
	// model.addElement("aab ");
	// model.addElement("aba ");
	// model.addElement("hpp ");
	// model.addElement("pp ");
	// model.addElement("hlp ");
	// frame.getContentPane().add(cmb);
	// frame.setSize(400, 80);
	// frame.setVisible(true);
	// }
}


/**
 * Aug 23, 2016
 * 
 * @author HHL 自动完成器。自动找到最匹配的项目,并排在列表的最前面。
 * 
 */
public class AutoCompleter implements KeyListener {

	private JComboBox owner = null;
	private JTextField editor = null;

	private ComboBoxModel model = null;

	private FreightSwing freightSwing = null;

	public AutoCompleter(JComboBox comboBox) {
		owner = comboBox;
		editor = (JTextField) comboBox.getEditor().getEditorComponent();
		editor.addKeyListener(this);
		model = comboBox.getModel();
		// owner.addItemListener(this);
	}

	public AutoCompleter(JComboBox comboBox, ItemListener itemListener,
			FreightSwing fs) {
		owner = comboBox;
		editor = (JTextField) comboBox.getEditor().getEditorComponent();
		editor.addKeyListener(this);
		model = comboBox.getModel();
		owner.addItemListener(itemListener);
		freightSwing = fs;
	}

	public void keyTyped(KeyEvent e) {
	}

	public void keyPressed(KeyEvent e) {
		char ch = e.getKeyChar();
		if (ch == KeyEvent.VK_ENTER) {
			return;
		}
		editor.setText("");
	}

	public void keyReleased(KeyEvent e) {
		char ch = e.getKeyChar();
		if (ch == KeyEvent.CHAR_UNDEFINED || Character.isISOControl(ch)
				|| ch == KeyEvent.VK_DELETE)
			return;

		int caretPosition = editor.getCaretPosition();
		String str = editor.getText();
		if (str.length() == 0)
			return;
		autoComplete(str, caretPosition);
	}

	/**
	 * 自动完成。根据输入的内容,在列表中找到相似的项目.
	 */
	protected void autoComplete(String strf, int caretPosition) {
		Object[] opts;
		opts = getMatchingOptions(strf.substring(0, caretPosition));
		if (owner != null) {
			model = new DefaultComboBoxModel(opts);
			owner.setModel(model);
		}
		if (opts.length > 0) {
			String str = opts[0].toString();
			// editor.setCaretPosition(caretPosition);
			if (owner != null) {
				try {
					owner.showPopup();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
		if (freightSwing != null) {
			freightSwing.itemChange();
		}
	}

	/**
	 * 
	 * 找到相似的项目, 并且将之排列到数组的最前面。
	 * 
	 * @param str
	 * @return 返回所有项目的列表。
	 */
	protected Object[] getMatchingOptions(String str) {
		List v = new Vector();
		List v1 = new Vector();
		model = owner.getModel();
		for (int k = 0; k < model.getSize(); k++) {
			Object itemObj = model.getElementAt(k);
			if (itemObj != null) {
				String itemObjA = PinYinUtil.getAlpha(itemObj.toString());
				String item = itemObjA.toString().toLowerCase();
				if (item.startsWith(str.toLowerCase()))
					v.add(model.getElementAt(k));
				else
					v1.add(model.getElementAt(k));
			} else
				v1.add(model.getElementAt(k));
		}
		for (int i = 0; i < v1.size(); i++) {
			v.add(v1.get(i));
		}
		if (v.isEmpty())
			v.add(str);
		return v.toArray();
	}

}



其中还用到了将汉字转换成汉语拼音的情况,String itemObjA = PinYinUtil.getAlpha(itemObj.toString()); 可以注释掉,该代码实现了输入首字母匹配字符串的作用。