Swing:支持自动过滤的 JComboBox

来源:互联网 发布:pi实时数据库 编辑:程序博客网 时间:2024/05/17 03:12

根据输入内容过滤可选项

支持键盘和鼠标的选择

 

package component;import java.awt.Component;import java.awt.event.FocusEvent;import java.awt.event.FocusListener;import java.awt.event.ItemEvent;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.util.Vector;import javax.swing.ComboBoxModel;import javax.swing.DefaultComboBoxModel;import javax.swing.JComboBox;import javax.swing.JComponent;import javax.swing.JFrame;import javax.swing.JList;import javax.swing.JPanel;import javax.swing.ListCellRenderer;import javax.swing.SwingUtilities;import javax.swing.event.ListDataEvent;import javax.swing.plaf.basic.BasicComboPopup;import javax.swing.plaf.basic.ComboPopup;import javax.swing.plaf.metal.MetalComboBoxUI;/** * 自动过滤下拉框 * @author Sun * */@SuppressWarnings("serial")public class JFilterComboBox extends JComboBox {/** * 显示用模型 */protected static DefaultComboBoxModel showModel = new DefaultComboBoxModel();/** * 正在选择 */private boolean selectingItem;/** * 创建一个 <code>JFilterComboBox</code>, * 其项取自现有的 <code>ComboBoxModel</code>。 * 由于提供了 <code>ComboBoxModel</code>, * 使用此构造方法创建的组合框不创建默认组合框模型, * 这可能影响插入、移除和添加方法的行为方式。 * @param aModel - 提供显示的项列表的 <code>ComboBoxModel</code> */public JFilterComboBox(ComboBoxModel aModel) {super(aModel);initialize();}/** * 创建包含指定数组中的元素的 <code>JFilterComboBox</code>。 * 默认情况下,选择数组中的第一项(因而也选择了该项的数据模型)。  * @param items - 要插入到组合框的对象数组 */public JFilterComboBox(final Object items[]) {super(items);initialize();}/** * 创建包含指定 <code>Vector</code> 中的元素的 <code>JFilterComboBox</code>。 * 默认情况下,选择数组中的第一项(因而也选择了该项的数据模型)。  * @param items - 要插入到组合框的向量数组 */public JFilterComboBox(Vector<?> items) {super(items);initialize();}/** * 创建具有默认数据模型的 <code>JFilterComboBox</code>。 * 默认的数据模型为空对象列表。使用 <code>addItem</code> 添加项。 * 默认情况下,选择数据模型中的第一项。 */public JFilterComboBox() {super();initialize();}private void initialize() {showModel.addListDataListener(this);}@Overridepublic void updateUI() {setUI(new MetalFilterComboBoxUI());ListCellRenderer renderer = getRenderer();if (renderer instanceof Component) {SwingUtilities.updateComponentTreeUI((Component) renderer);}}@Overridepublic Object getSelectedItem() {return showModel.getSelectedItem();}@Overridepublic void setSelectedItem(Object anObject) {Object oldSelection = selectedItemReminder;Object objectToSelect = anObject;if (oldSelection == null || !oldSelection.equals(anObject)) {if (anObject != null && !isEditable()) {boolean found = false;for (int i = 0; i < showModel.getSize(); i++) {Object element = showModel.getElementAt(i);if (anObject.equals(element)) {found = true;objectToSelect = element;break;}}if (!found) {return;}}selectingItem = true;showModel.setSelectedItem(objectToSelect);selectingItem = false;if (selectedItemReminder != showModel.getSelectedItem()) {selectedItemChanged();}}fireActionEvent();}@Overridepublic void setSelectedIndex(int anIndex) {int size = showModel.getSize();if (anIndex == -1 || size == 0) {setSelectedItem(null);} else if (anIndex < -1) {throw new IllegalArgumentException("setSelectedIndex: " + anIndex+ " out of bounds");} else if (anIndex >= size) {setSelectedItem(showModel.getElementAt(size - 1));} else {setSelectedItem(showModel.getElementAt(anIndex));}}@Overridepublic int getSelectedIndex() {Object sObject = showModel.getSelectedItem();int i, c;Object obj;for (i = 0, c = showModel.getSize(); i < c; i++) {obj = showModel.getElementAt(i);if (obj != null && obj.equals(sObject))return i;}return -1;}@Overridepublic void contentsChanged(ListDataEvent e) {Object oldSelection = selectedItemReminder;Object newSelection = showModel.getSelectedItem();if (oldSelection == null || !oldSelection.equals(newSelection)) {selectedItemChanged();if (!selectingItem) {fireActionEvent();}}}@Overrideprotected void selectedItemChanged() {if (selectedItemReminder != null) {fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, selectedItemReminder,ItemEvent.DESELECTED));}selectedItemReminder = showModel.getSelectedItem();if (selectedItemReminder != null) {fireItemStateChanged(new ItemEvent(this,ItemEvent.ITEM_STATE_CHANGED, selectedItemReminder,ItemEvent.SELECTED));}}@Overridepublic void intervalAdded(ListDataEvent e) {if (selectedItemReminder != showModel.getSelectedItem()) {selectedItemChanged();}}@Overridepublic void setEditable(boolean aFlag) {super.setEditable(true);}/** * 返回显示用模型 * @return */public DefaultComboBoxModel getShowModel() {return showModel;}/** * Metal L&F 风格的 UI 类 * @author Sun * */class MetalFilterComboBoxUI extends MetalComboBoxUI {/** * 编辑区事件监听器 */protected EditorListener editorListener;/** * 该 UI 类负责绘制的控件 */protected JFilterComboBox filterComboBox;@Overridepublic void installUI(JComponent c) {filterComboBox = (JFilterComboBox) c;filterComboBox.setEditable(true);super.installUI(c);}@Overridepublic void configureEditor() {super.configureEditor();editor.addKeyListener(getEditorListener());editor.addMouseListener(getEditorListener());editor.addFocusListener(getEditorListener());}@Overridepublic void unconfigureEditor() {super.unconfigureEditor();if (editorListener != null) {editor.removeKeyListener(editorListener);editor.removeMouseListener(editorListener);editor.removeFocusListener(editorListener);editorListener = null;}}@Overrideprotected ComboPopup createPopup() {return new FilterComboPopup(filterComboBox);}/** * 初始化并返回编辑区事件监听器 * @return */protected EditorListener getEditorListener() {if (editorListener == null) {editorListener = new EditorListener();}return editorListener;}/** * 按关键字进行查询,该方法中,可以自行加入各种查询算法 */protected void findMatchs() {ComboBoxModel model = filterComboBox.getModel();DefaultComboBoxModel showModel = filterComboBox.getShowModel();showModel.removeAllElements();for (int i = 0; i < model.getSize(); i++) {String name = model.getElementAt(i).toString();if (name.indexOf(getEditorText()) >= 0) {showModel.addElement(model.getElementAt(i));}}((FilterComboPopup)popup ).repaint();}/** * 返回编辑区文本 * @return */private String getEditorText() {return filterComboBox.getEditor().getItem().toString();}/** * 弹出面板类 * @author Sun * */class FilterComboPopup extends BasicComboPopup {public FilterComboPopup(JComboBox combo) {super(combo);}@Overrideprotected JList createList() {JList list = super.createList();list.setModel(filterComboBox.getShowModel());return list;}@Overridepublic void setVisible(boolean b) {super.setVisible(b);if (!b) {comboBox.getEditor().setItem(comboBox.getSelectedItem());}}@Overridepublic void show() {findMatchs();super.show();}}/** * 编辑区事件监听器类 * @author Sun * */class EditorListener implements KeyListener,MouseListener, FocusListener {/** * 旧文本,用于键盘输入时的比对 */private String oldText = "";@Overridepublic void keyReleased(KeyEvent e) {String newText = getEditorText();if (!newText.equals(oldText)) {findMatchs();}}@Overridepublic void keyPressed(KeyEvent e) {oldText = getEditorText();if (!isPopupVisible(filterComboBox)) {setPopupVisible(filterComboBox, true);}}@Overridepublic void keyTyped(KeyEvent e) {findMatchs();}@Overridepublic void mouseClicked(MouseEvent e) {}@Overridepublic void mousePressed(MouseEvent e) {if (!isPopupVisible(filterComboBox)) {setPopupVisible(filterComboBox, true);}}@Overridepublic void mouseReleased(MouseEvent e) {}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}@Overridepublic void focusGained(FocusEvent e) {if (!isPopupVisible(filterComboBox)) {setPopupVisible(filterComboBox, true);}}@Overridepublic void focusLost(FocusEvent e) {}}}/** * 使用示例 * @param args */public static void main(String... args) {Vector<String> data = new Vector<String>(0);data.add("ab");data.add("ac");data.add("bb");data.add("cc");JPanel panel = new JPanel();panel.add(new JFilterComboBox(data));JFrame frame = new JFrame();frame.setSize(400, 300);frame.setLocationRelativeTo(null);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setContentPane(panel);frame.setVisible(true);}}