public class FilterableComboBox<T> extends JComboBox
{
private interface Filter
{
public boolean accept(Object obj);
}
//去掉:表格中显示问题
// public void setItem(final Object item)
// {
// super.setSelectedItem(item);
// }
//
// @Override
// public void setSelectedItem(final Object item)
// {
// if (item != null)
// {
// setSelectedItem(item.toString());
// return;
// }
//
// super.setSelectedItem(item);
// }
//
// public void setSelectedItem(final String item)
// {
// super.setSelectedItem(getFilterItem(item));
// }
private class FilterableComboBoxModel extends AbstractListModel implements MutableComboBoxModel
{
private static final long serialVersionUID = -8893609766963132266L;
private T selectedItem;
public FilterableComboBoxModel(final List<T> items)
{
this.addElementList(items);
FilterableComboBox.this.isInitialed = true;
}
@SuppressWarnings("unused")
public FilterableComboBoxModel(final T[] items)
{
this.addElementList(items);
FilterableComboBox.this.isInitialed = true;
}
@Override
@SuppressWarnings("unchecked")
public void addElement(final Object item)
{
FilterableComboBox.this.allItems.add((T) item);
this.updateAddedItem((T) item);
}
@SuppressWarnings("unused")
public void addElement(final T[] items)
{
if ((items == null) || (items.length == 0))
{
return;
}
for (T tmp : items)
{
FilterableComboBox.this.allItems.add(tmp);
}
this.updateAddedItems(items);
}
private void addElementList(final Collection<T> items)
{
if ((items == null) || (items.size() == 0))
{
return;
}
FilterableComboBox.this.allItems.addAll(items);
this.updateAddedItems(items);
}
private void addElementList(final T[] items)
{
if ((items == null) || (items.length == 0))
{
return;
}
for (T tmp : items)
{
FilterableComboBox.this.allItems.add(tmp);
}
this.updateAddedItems(items);
}
@Override
public void fireIntervalAdded(final Object source, final int index0, final int index1)
{
super.fireIntervalAdded(source, index0, index1);
}
@Override
public void fireIntervalRemoved(final Object source, final int index0, final int index1)
{
super.fireIntervalRemoved(source, index0, index1);
}
@Override
public Object getElementAt(final int index)
{
if (index < 0)
{
return null;
}
if (FilterableComboBox.this.filteredItems.size() <= index)
{
return null;
}
return FilterableComboBox.this.filteredItems.get(index);
}
@Override
public T getSelectedItem()
{
if ((this.selectedItem == null) || (this.selectedItem.toString().isEmpty()))
{
return null;
}
return this.selectedItem;
}
@Override
public int getSize()
{
return FilterableComboBox.this.filteredItems.size();
}
@Override
public void insertElementAt(final Object obj, final int index)
{
throw new UnsupportedOperationException("Operation 'insertElementAt' Not supported!");
}
@Override
@SuppressWarnings("unchecked")
public void removeElement(final Object item)
{
if (item == null)
{
return;
}
int index = FilterableComboBox.this.filteredItems.indexOf(item);
if (index < 0)
{
return;
}
this.removeOneElement((T) item, index);
}
@Override
public void removeElementAt(final int index)
{
if (index < 0)
{
return;
}
T item = FilterableComboBox.this.allItems.get(index);
if (item == null)
{
return;
}
this.removeOneElement(item, index);
}
private synchronized void removeOneElement(final T item, final int index)
{
FilterableComboBox.this.allItems.remove(item);
FilterableComboBox.this.filteredItems.remove(index);
if (item == this.selectedItem)
{
if (index > 0)
{
this.selectedItem = FilterableComboBox.this.filteredItems.get(index - 1);
FilterableComboBox.this.cmbEditor.setItem(this.selectedItem);
}
else
{
this.selectedItem = null;
FilterableComboBox.this.cmbEditor.setItem(null);
}
}
this.updateRemovedItem(item);
}
private T searchExact()
{
T selectedItem = null;
if (this.selectedItem == null)
{
for (T item : FilterableComboBox.this.filteredItems)
{
if (item.toString().indexOf(FilterableComboBox.this.orginStr) >= 0)
{
selectedItem = item;
break;
}
}
}
else
{
if (this.selectedItem.toString().indexOf(FilterableComboBox.this.orginStr) < 0)
{
for (T item : FilterableComboBox.this.filteredItems)
{
if (item.toString().indexOf(FilterableComboBox.this.orginStr) >= 0)
{
selectedItem = item;
break;
}
}
}
else
{
selectedItem = this.selectedItem;
}
}
if ((selectedItem == null) && (FilterableComboBox.this.filteredItems.size() > 0))
{
selectedItem = FilterableComboBox.this.filteredItems.get(0);
}
return selectedItem;
}
private void searchIgnoreCase()
{
for (T item : FilterableComboBox.this.allItems)
{
if (FilterableComboBox.this.filter.accept(item))
{
FilterableComboBox.this.filteredItems.add(item);
}
}
}
@Override
@SuppressWarnings("unchecked")
public void setSelectedItem(final Object item)
{
if (!allowedMismatch && filtering)
{
if (this.selectedItem == null)
{
text.setText("");
return;
}
}
this.setSelectedObject((T) item);
this.fireContentsChanged(this, -1, -1);
}
private void setSelectedObject(final T item)
{
if ((this.selectedItem == null) && (item == null))
{
return;
}
if ((this.selectedItem != null) && this.selectedItem.toString().equals(item))
{
return;
}
if ((item != null) && item.toString().equals(this.selectedItem))
{
return;
}
this.selectedItem = item;
}
private void updateAddedItem(final T item)
{
if (FilterableComboBox.this.isInitialed == false)
{
FilterableComboBox.this.filteredItems.add(item);
}
else
{
this.updateFilteredItems();
}
}
private void updateAddedItems(final Collection<T> items)
{
if (FilterableComboBox.this.isInitialed == false)
{
FilterableComboBox.this.filteredItems.addAll(items);
}
else
{
this.updateFilteredItems();
}
}
private void updateAddedItems(final T[] items)
{
if (FilterableComboBox.this.isInitialed == false)
{
for (T item : items)
{
FilterableComboBox.this.filteredItems.add(item);
}
}
else
{
this.updateFilteredItems();
}
}
private void updateFilteredItems()
{
if (FilterableComboBox.this.freezeFilter)
{
return;
}
T selectedItem = null;
FilterableComboBox.this.filteredItems.clear();
if (FilterableComboBox.this.filter == null)
{
FilterableComboBox.this.filteredItems.addAll(FilterableComboBox.this.allItems);
}
else
{
this.searchIgnoreCase();
if ((FilterableComboBox.this.filteredItems.size() > 0) && (FilterableComboBox.this.orginStr != null))
{
selectedItem = this.searchExact();
}
}
if (FilterableComboBox.this.oldItem != selectedItem)
{
this.setSelectedObject(selectedItem);
FilterableComboBox.this.changed = true;
}
else
{
FilterableComboBox.this.changed = false;
}
// TODO:这里的算法需要重新整理
if (selectedItem == null)
{
if (FilterableComboBox.this.cmbEditor.getItem().toString().length() > 0)
{
FilterableComboBox.this.changed = true;
}
if (FilterableComboBox.this.filter != null)
{
FilterableComboBox.this.filteredItems.addAll(FilterableComboBox.this.allItems);
}
else
{
}
if ((FilterableComboBox.this.oldItem != FilterableComboBox.this.defaultItem)
&& (FilterableComboBox.this.defaultItem != null))
{
this.setSelectedItem(FilterableComboBox.this.defaultItem);
FilterableComboBox.this.changed = true;
}
else
{
FilterableComboBox.this.changed = false;
}
}
else
{
if (!FilterableComboBox.this.cmbEditor.getItem().toString().equals(selectedItem.toString()))
{
FilterableComboBox.this.changed = true;
}
}
FilterableComboBox.this.updateComboBox();
}
private void updateRemovedItem(final T item)
{
if (FilterableComboBox.this.isInitialed == false)
{
this.updateFilteredItems();
}
}
}
protected JTextField getTextEditor()
{
return new JTextField(32);
}
protected class FilterableEditor extends BasicComboBoxEditor implements ComboBoxEditor
{
public FilterableEditor()
{
FilterableComboBox.this.text = getTextEditor();
// FilterableComboBox.this.text.setBorder(new EmptyBorder(1, 1, 1, 1));
FilterableComboBox.this.text.addKeyListener(FilterableComboBox.this.keyListener);
FilterableComboBox.this.text.addFocusListener(FilterableComboBox.this.focusListener);
FilterableComboBox.this.text.getDocument().addDocumentListener(FilterableComboBox.this.documentListener);
}
@Override
public void addActionListener(final ActionListener l)
{
FilterableComboBox.this.text.addActionListener(l);
}
@Override
public Component getEditorComponent()
{
return FilterableComboBox.this.text;
}
@Override
public Object getItem()
{
return FilterableComboBox.this.text.getText();
}
@Override
public void removeActionListener(final ActionListener l)
{
FilterableComboBox.this.text.removeActionListener(l);
}
@Override
public void selectAll()
{
FilterableComboBox.this.text.selectAll();
}
@Override
public void setItem(final Object item)
{
if (FilterableComboBox.this.freezeFilter)
{
this.setItemValue(item);
return;
}
if (FilterableComboBox.this.filtering)
{
return;
}
// 如果下拉框选项正在改变则不过滤
// if (!changed)
// {
FilterableComboBox.this.setting = true;
this.setItemValue(item);
FilterableComboBox.this.setting = false;
// }
}
private void setItemValue(final Object item)
{
String newText = (item == null) ? "" : item.toString();
FilterableComboBox.this.text.setText(newText);
}
}
private class StartsWithFilter implements Filter
{
private final String filterStr;
public StartsWithFilter(final String prefix)
{
this.filterStr = prefix.toLowerCase();
}
@Override
public boolean accept(final Object o)
{
return o.toString().toLowerCase().indexOf(this.filterStr) >= 0;
}
}
/**
* 所有下拉菜单项
*/
private final List<T> allItems = new ArrayList<T>();
/**
* 已经过滤出来的下拉菜单项
*/
private final List<T> filteredItems = new ArrayList<T>();
protected FilterableComboBoxModel cmbModel = new FilterableComboBoxModel(this.filteredItems);
/**
* 编辑器
*/
protected transient BasicComboBoxEditor cmbEditor = null;;
/**
* 过滤器
*/
private Filter filter = null;
/**
* 正在过滤
*/
protected volatile boolean filtering = false;
/**
* 正在设值
*/
protected volatile boolean setting = false;
/**
* 禁止过滤
*/
protected boolean freezeFilter = false;
protected JTextField text = null;
/**
* 是否已经初始化,如果为false,则下拉框禁用过滤等等监听事件,在下拉框初始化大数据时有用
*/
private boolean isInitialed = false;
/**
* 下拉框滚动条一页显示的数据个数
*/
private static final int MAXROWCOUNT = 8;
private volatile T defaultItem = null;
private boolean bItemListenerAdded = false;
private volatile Object oldItem = null;
private volatile boolean changed = false;
/**
* 是否允许不匹配的项
*/
private boolean allowedMismatch = true;
protected transient FocusListener focusListener = new FocusAdapter()
{
@Override
public void focusGained(final FocusEvent e)
{
FilterableComboBox.this.text.selectAll();
FilterableComboBox.this.oldItem = FilterableComboBox.this.cmbModel.getSelectedItem();
}
@Override
public void focusLost(final FocusEvent e)
{
if (FilterableComboBox.this.freezeFilter)
{
return;
}
Object item = FilterableComboBox.this.cmbModel.getSelectedItem();
if ((item == null) && (!allowedMismatch))
{
text.setText("");
}
else
{
FilterableComboBox.this.changeSelect(item);
}
if (FilterableComboBox.this.filteredItems.size() == 0)
{
FilterableComboBox.this.reloadComboBox();
}
}
};
/**
* JComboBoxcellrenderer.
*/
private DefaultListCellRenderer listCellRenderer = new DefaultListCellRenderer()
{
private static final long serialVersionUID = -7330621790373229915L;
// 重写它的方法:
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus)
{
if (value == null)
{
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
list.setToolTipText(value.toString());
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
};
protected transient KeyListener keyListener = new KeyAdapter()
{
@Override
public void keyPressed(final KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_F4)
{
FilterableComboBox.this.setPopupVisible(!FilterableComboBox.this.isPopupVisible());
FilterableComboBox.this.text.selectAll();
return;
}
if (FilterableComboBox.this.freezeFilter)
{
return;
}
Object item = FilterableComboBox.this.cmbModel.getSelectedItem();
if ((e.getKeyCode() == KeyEvent.VK_ENTER) || (e.getKeyCode() == KeyEvent.VK_TAB))
{
FilterableComboBox.this.changeSelect(item);
if (FilterableComboBox.this.filteredItems.size() == 0)
{
FilterableComboBox.this.reloadComboBox();
}
}
}
@Override
public void keyReleased(final KeyEvent e)
{
if ((e.getKeyCode() == KeyEvent.VK_ENTER) && (FilterableComboBox.this.cmbModel.getSelectedItem() == null))
{
try
{
FilterableComboBox.this.setPopupVisible(true);
}
catch (Exception ex)
{
}
}
}
};
protected DocumentListener documentListener = new DocumentListener()
{
@Override
public void changedUpdate(final DocumentEvent e)
{
}
@Override
public void insertUpdate(final DocumentEvent e)
{
try
{
FilterableComboBox.this.handleChange();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void removeUpdate(final DocumentEvent e)
{
try
{
FilterableComboBox.this.handleChange();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
};
private String orginStr = null;
private final ItemListener itemListener = new ItemListener()
{
@Override
public void itemStateChanged(final ItemEvent e)
{
if (e.getStateChange() == ItemEvent.SELECTED)
{
FilterableComboBox.this.fireActionPerformed();
}
}
};
public FilterableComboBox()
{
this.init();
this.setEditable(true);
}
// @Override
// public boolean requestFocus(boolean temporary)
// {
// super.requestFocus(temporary);
// this.text.selectAll();
// return this.text.requestFocus(temporary);
// }
//
// @Override
// public boolean requestFocusInWindow(boolean temporary)
// {
// super.requestFocusInWindow(temporary);
// this.text.selectAll();
// return this.text.requestFocus(temporary);
// }
//
// @Override
// public void requestFocus()
// {
// super.requestFocus();
// this.text.requestFocus();
// this.text.selectAll();
// }
//
// @Override
// public boolean requestFocusInWindow()
// {
// super.requestFocusInWindow();
// this.text.selectAll();
// return this.text.requestFocusInWindow();
// }
public FilterableComboBox(final BasicComboBoxEditor editor)
{
this.setModel(this.cmbModel);
this.cmbEditor = editor;
this.text = (JTextField) this.cmbEditor.getEditorComponent();
// this.text.setBorder(BorderFactory.createEmptyBorder());
this.text.addFocusListener(this.focusListener);
this.addKeyListener(this.keyListener);
this.text.addKeyListener(this.keyListener);
this.text.getDocument().addDocumentListener(this.documentListener);
this.setEditor(this.cmbEditor);
this.setRenderer(this.listCellRenderer);
this.setEditable(true);
}
public FilterableComboBox(final List<T> items)
{
this.init();
this.addItems(items);
this.setEditable(true);
this.isInitialed = true;
}
public FilterableComboBox(final T[] items)
{
this.init();
this.addItems(items);
this.setEditable(true);
this.isInitialed = true;
}
@Override
public void addActionListener(final ActionListener l)
{
if (!this.freezeFilter && !this.bItemListenerAdded)
{
this.addItemListener(this.itemListener);
this.bItemListenerAdded = true;
}
super.addActionListener(l);
}
/**
* @see javax.swing.JComboBox#addItem(java.lang.Object)
*/
@Override
public void addItem(final Object item)
{
this.addItem(item, false);
}
public void addItem(final Object item, final boolean isCheck)
{
if (isCheck)
{
if (!this.allItems.contains(item))
{
this.cmbModel.addElement(item);
}
}
else
{
this.cmbModel.addElement(item);
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
public void addItems(final Collection<T> items)
{
this.addItems(items, false);
}
public void addItems(final Collection<T> items, final boolean isCheck)
{
if ((items == null) || (items.size() == 0))
{
return;
}
if (isCheck)
{
for (T tmp : items)
{
if (!this.allItems.contains(tmp))
{
this.cmbModel.addElement(tmp);
}
}
}
else
{
this.cmbModel.addElementList(items);
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
public void addItems(final T[] items)
{
this.addItems(items, false);
}
public void addItems(final T[] items, final boolean isCheck)
{
if ((items == null) || (items.length == 0))
{
return;
}
if (isCheck)
{
for (T tmp : items)
{
if (!this.allItems.contains(tmp))
{
this.cmbModel.addElement(tmp);
}
}
}
else
{
for (Object tmp : items)
{
this.cmbModel.addElement(tmp);
}
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
private void changeSelect(final Object item)
{
if (this.changed)
{
this.cmbEditor.setItem(item);
this.cmbModel.setSelectedItem(item);
this.oldItem = item;
this.changed = false;
}
}
@Override
public void fireActionEvent()
{
if (this.freezeFilter)
{
super.fireActionEvent();
}
}
private void fireActionPerformed()
{
super.fireActionEvent();
}
private void fixMaxVisibleItemCount()
{
if (this.filteredItems.size() < FilterableComboBox.MAXROWCOUNT)
{
this.setMaximumRowCount(this.filteredItems.size());
}
else
{
this.setMaximumRowCount(FilterableComboBox.MAXROWCOUNT);
}
}
/**
* 根据字符串查找出一个Item.<br/>
*
* @param filterStr
* @return T
*/
public T getFilterItem(final String filterStr)
{
Filter tmpFilter = new StartsWithFilter(filterStr);
for (T item : this.allItems)
{
if (tmpFilter.accept(item))
{
return item;
}
}
return null;
}
@Override
public T getSelectedItem()
{
return this.cmbModel.getSelectedItem();
}
protected void handleChange()
{
if (this.freezeFilter)
{
return;
}
if (this.setting)
{
return;
}
this.filtering = true;
Filter filter = null;
if (this.text.getText().length() > 0)
{
this.orginStr = this.text.getText();
filter = new StartsWithFilter(this.orginStr);
}
else
{
this.orginStr = null;
}
this.setFilter(filter);
// A bit nasty but it seems to get the popup validated properly
// setPopupVisible(false);
if (this.filteredItems.size() > 0)
{
this.setPopupVisible(true);
}
else
{
this.setPopupVisible(false);
}
this.filtering = false;
}
private void init()
{
this.setModel(this.cmbModel);
this.cmbEditor = new FilterableEditor();
this.setEditor(this.cmbEditor);
this.setRenderer(this.listCellRenderer);
this.addKeyListener(this.keyListener);
}
public boolean isInitialed()
{
return this.isInitialed;
}
private void reloadComboBox()
{
this.setting = true;
if (this.filteredItems.size() < this.allItems.size())
{
this.filteredItems.clear();
this.filteredItems.addAll(this.allItems);
this.updateComboBox();
}
this.setting = false;
}
@Override
public void removeAllItems()
{
super.removeAllItems();
this.filteredItems.clear();
this.allItems.clear();
}
@Override
public void removeItem(final Object item)
{
this.allItems.remove(item);
this.cmbModel.removeElement(item);
if (this.isInitialed == false)
{
this.fixMaxVisibleItemCount();
this.cmbModel.fireIntervalRemoved(this, 0, this.cmbModel.getSize() - 1);
}
}
@Override
public void removeItemAt(final int index)
{
if (index < 0)
{
return;
}
if (index >= this.cmbModel.getSize())
{
return;
}
Object item = this.cmbModel.getElementAt(index);
this.removeItem(item);
}
@Override
protected void selectedItemChanged()
{
if (this.freezeFilter || (this.filtering == false))
{
super.selectedItemChanged();
}
}
public void setDefaultItem(final T defaultItem)
{
this.defaultItem = defaultItem;
}
public void setAllowedMismatch(final boolean allowedMismatch)
{
this.allowedMismatch = allowedMismatch;
}
private void setFilter(final Filter filter)
{
this.filter = filter;
this.cmbModel.updateFilteredItems();
}
public void setIsInitialed(final boolean isInitialed)
{
this.isInitialed = isInitialed;
if (this.isInitialed)
{
this.updateComboBox();
}
}
private void updateComboBox()
{
this.fixMaxVisibleItemCount();
this.cmbModel.fireIntervalAdded(this, 0, this.filteredItems.size());
}
{
private interface Filter
{
public boolean accept(Object obj);
}
//去掉:表格中显示问题
// public void setItem(final Object item)
// {
// super.setSelectedItem(item);
// }
//
// @Override
// public void setSelectedItem(final Object item)
// {
// if (item != null)
// {
// setSelectedItem(item.toString());
// return;
// }
//
// super.setSelectedItem(item);
// }
//
// public void setSelectedItem(final String item)
// {
// super.setSelectedItem(getFilterItem(item));
// }
private class FilterableComboBoxModel extends AbstractListModel implements MutableComboBoxModel
{
private static final long serialVersionUID = -8893609766963132266L;
private T selectedItem;
public FilterableComboBoxModel(final List<T> items)
{
this.addElementList(items);
FilterableComboBox.this.isInitialed = true;
}
@SuppressWarnings("unused")
public FilterableComboBoxModel(final T[] items)
{
this.addElementList(items);
FilterableComboBox.this.isInitialed = true;
}
@Override
@SuppressWarnings("unchecked")
public void addElement(final Object item)
{
FilterableComboBox.this.allItems.add((T) item);
this.updateAddedItem((T) item);
}
@SuppressWarnings("unused")
public void addElement(final T[] items)
{
if ((items == null) || (items.length == 0))
{
return;
}
for (T tmp : items)
{
FilterableComboBox.this.allItems.add(tmp);
}
this.updateAddedItems(items);
}
private void addElementList(final Collection<T> items)
{
if ((items == null) || (items.size() == 0))
{
return;
}
FilterableComboBox.this.allItems.addAll(items);
this.updateAddedItems(items);
}
private void addElementList(final T[] items)
{
if ((items == null) || (items.length == 0))
{
return;
}
for (T tmp : items)
{
FilterableComboBox.this.allItems.add(tmp);
}
this.updateAddedItems(items);
}
@Override
public void fireIntervalAdded(final Object source, final int index0, final int index1)
{
super.fireIntervalAdded(source, index0, index1);
}
@Override
public void fireIntervalRemoved(final Object source, final int index0, final int index1)
{
super.fireIntervalRemoved(source, index0, index1);
}
@Override
public Object getElementAt(final int index)
{
if (index < 0)
{
return null;
}
if (FilterableComboBox.this.filteredItems.size() <= index)
{
return null;
}
return FilterableComboBox.this.filteredItems.get(index);
}
@Override
public T getSelectedItem()
{
if ((this.selectedItem == null) || (this.selectedItem.toString().isEmpty()))
{
return null;
}
return this.selectedItem;
}
@Override
public int getSize()
{
return FilterableComboBox.this.filteredItems.size();
}
@Override
public void insertElementAt(final Object obj, final int index)
{
throw new UnsupportedOperationException("Operation 'insertElementAt' Not supported!");
}
@Override
@SuppressWarnings("unchecked")
public void removeElement(final Object item)
{
if (item == null)
{
return;
}
int index = FilterableComboBox.this.filteredItems.indexOf(item);
if (index < 0)
{
return;
}
this.removeOneElement((T) item, index);
}
@Override
public void removeElementAt(final int index)
{
if (index < 0)
{
return;
}
T item = FilterableComboBox.this.allItems.get(index);
if (item == null)
{
return;
}
this.removeOneElement(item, index);
}
private synchronized void removeOneElement(final T item, final int index)
{
FilterableComboBox.this.allItems.remove(item);
FilterableComboBox.this.filteredItems.remove(index);
if (item == this.selectedItem)
{
if (index > 0)
{
this.selectedItem = FilterableComboBox.this.filteredItems.get(index - 1);
FilterableComboBox.this.cmbEditor.setItem(this.selectedItem);
}
else
{
this.selectedItem = null;
FilterableComboBox.this.cmbEditor.setItem(null);
}
}
this.updateRemovedItem(item);
}
private T searchExact()
{
T selectedItem = null;
if (this.selectedItem == null)
{
for (T item : FilterableComboBox.this.filteredItems)
{
if (item.toString().indexOf(FilterableComboBox.this.orginStr) >= 0)
{
selectedItem = item;
break;
}
}
}
else
{
if (this.selectedItem.toString().indexOf(FilterableComboBox.this.orginStr) < 0)
{
for (T item : FilterableComboBox.this.filteredItems)
{
if (item.toString().indexOf(FilterableComboBox.this.orginStr) >= 0)
{
selectedItem = item;
break;
}
}
}
else
{
selectedItem = this.selectedItem;
}
}
if ((selectedItem == null) && (FilterableComboBox.this.filteredItems.size() > 0))
{
selectedItem = FilterableComboBox.this.filteredItems.get(0);
}
return selectedItem;
}
private void searchIgnoreCase()
{
for (T item : FilterableComboBox.this.allItems)
{
if (FilterableComboBox.this.filter.accept(item))
{
FilterableComboBox.this.filteredItems.add(item);
}
}
}
@Override
@SuppressWarnings("unchecked")
public void setSelectedItem(final Object item)
{
if (!allowedMismatch && filtering)
{
if (this.selectedItem == null)
{
text.setText("");
return;
}
}
this.setSelectedObject((T) item);
this.fireContentsChanged(this, -1, -1);
}
private void setSelectedObject(final T item)
{
if ((this.selectedItem == null) && (item == null))
{
return;
}
if ((this.selectedItem != null) && this.selectedItem.toString().equals(item))
{
return;
}
if ((item != null) && item.toString().equals(this.selectedItem))
{
return;
}
this.selectedItem = item;
}
private void updateAddedItem(final T item)
{
if (FilterableComboBox.this.isInitialed == false)
{
FilterableComboBox.this.filteredItems.add(item);
}
else
{
this.updateFilteredItems();
}
}
private void updateAddedItems(final Collection<T> items)
{
if (FilterableComboBox.this.isInitialed == false)
{
FilterableComboBox.this.filteredItems.addAll(items);
}
else
{
this.updateFilteredItems();
}
}
private void updateAddedItems(final T[] items)
{
if (FilterableComboBox.this.isInitialed == false)
{
for (T item : items)
{
FilterableComboBox.this.filteredItems.add(item);
}
}
else
{
this.updateFilteredItems();
}
}
private void updateFilteredItems()
{
if (FilterableComboBox.this.freezeFilter)
{
return;
}
T selectedItem = null;
FilterableComboBox.this.filteredItems.clear();
if (FilterableComboBox.this.filter == null)
{
FilterableComboBox.this.filteredItems.addAll(FilterableComboBox.this.allItems);
}
else
{
this.searchIgnoreCase();
if ((FilterableComboBox.this.filteredItems.size() > 0) && (FilterableComboBox.this.orginStr != null))
{
selectedItem = this.searchExact();
}
}
if (FilterableComboBox.this.oldItem != selectedItem)
{
this.setSelectedObject(selectedItem);
FilterableComboBox.this.changed = true;
}
else
{
FilterableComboBox.this.changed = false;
}
// TODO:这里的算法需要重新整理
if (selectedItem == null)
{
if (FilterableComboBox.this.cmbEditor.getItem().toString().length() > 0)
{
FilterableComboBox.this.changed = true;
}
if (FilterableComboBox.this.filter != null)
{
FilterableComboBox.this.filteredItems.addAll(FilterableComboBox.this.allItems);
}
else
{
}
if ((FilterableComboBox.this.oldItem != FilterableComboBox.this.defaultItem)
&& (FilterableComboBox.this.defaultItem != null))
{
this.setSelectedItem(FilterableComboBox.this.defaultItem);
FilterableComboBox.this.changed = true;
}
else
{
FilterableComboBox.this.changed = false;
}
}
else
{
if (!FilterableComboBox.this.cmbEditor.getItem().toString().equals(selectedItem.toString()))
{
FilterableComboBox.this.changed = true;
}
}
FilterableComboBox.this.updateComboBox();
}
private void updateRemovedItem(final T item)
{
if (FilterableComboBox.this.isInitialed == false)
{
this.updateFilteredItems();
}
}
}
protected JTextField getTextEditor()
{
return new JTextField(32);
}
protected class FilterableEditor extends BasicComboBoxEditor implements ComboBoxEditor
{
public FilterableEditor()
{
FilterableComboBox.this.text = getTextEditor();
// FilterableComboBox.this.text.setBorder(new EmptyBorder(1, 1, 1, 1));
FilterableComboBox.this.text.addKeyListener(FilterableComboBox.this.keyListener);
FilterableComboBox.this.text.addFocusListener(FilterableComboBox.this.focusListener);
FilterableComboBox.this.text.getDocument().addDocumentListener(FilterableComboBox.this.documentListener);
}
@Override
public void addActionListener(final ActionListener l)
{
FilterableComboBox.this.text.addActionListener(l);
}
@Override
public Component getEditorComponent()
{
return FilterableComboBox.this.text;
}
@Override
public Object getItem()
{
return FilterableComboBox.this.text.getText();
}
@Override
public void removeActionListener(final ActionListener l)
{
FilterableComboBox.this.text.removeActionListener(l);
}
@Override
public void selectAll()
{
FilterableComboBox.this.text.selectAll();
}
@Override
public void setItem(final Object item)
{
if (FilterableComboBox.this.freezeFilter)
{
this.setItemValue(item);
return;
}
if (FilterableComboBox.this.filtering)
{
return;
}
// 如果下拉框选项正在改变则不过滤
// if (!changed)
// {
FilterableComboBox.this.setting = true;
this.setItemValue(item);
FilterableComboBox.this.setting = false;
// }
}
private void setItemValue(final Object item)
{
String newText = (item == null) ? "" : item.toString();
FilterableComboBox.this.text.setText(newText);
}
}
private class StartsWithFilter implements Filter
{
private final String filterStr;
public StartsWithFilter(final String prefix)
{
this.filterStr = prefix.toLowerCase();
}
@Override
public boolean accept(final Object o)
{
return o.toString().toLowerCase().indexOf(this.filterStr) >= 0;
}
}
/**
* 所有下拉菜单项
*/
private final List<T> allItems = new ArrayList<T>();
/**
* 已经过滤出来的下拉菜单项
*/
private final List<T> filteredItems = new ArrayList<T>();
protected FilterableComboBoxModel cmbModel = new FilterableComboBoxModel(this.filteredItems);
/**
* 编辑器
*/
protected transient BasicComboBoxEditor cmbEditor = null;;
/**
* 过滤器
*/
private Filter filter = null;
/**
* 正在过滤
*/
protected volatile boolean filtering = false;
/**
* 正在设值
*/
protected volatile boolean setting = false;
/**
* 禁止过滤
*/
protected boolean freezeFilter = false;
protected JTextField text = null;
/**
* 是否已经初始化,如果为false,则下拉框禁用过滤等等监听事件,在下拉框初始化大数据时有用
*/
private boolean isInitialed = false;
/**
* 下拉框滚动条一页显示的数据个数
*/
private static final int MAXROWCOUNT = 8;
private volatile T defaultItem = null;
private boolean bItemListenerAdded = false;
private volatile Object oldItem = null;
private volatile boolean changed = false;
/**
* 是否允许不匹配的项
*/
private boolean allowedMismatch = true;
protected transient FocusListener focusListener = new FocusAdapter()
{
@Override
public void focusGained(final FocusEvent e)
{
FilterableComboBox.this.text.selectAll();
FilterableComboBox.this.oldItem = FilterableComboBox.this.cmbModel.getSelectedItem();
}
@Override
public void focusLost(final FocusEvent e)
{
if (FilterableComboBox.this.freezeFilter)
{
return;
}
Object item = FilterableComboBox.this.cmbModel.getSelectedItem();
if ((item == null) && (!allowedMismatch))
{
text.setText("");
}
else
{
FilterableComboBox.this.changeSelect(item);
}
if (FilterableComboBox.this.filteredItems.size() == 0)
{
FilterableComboBox.this.reloadComboBox();
}
}
};
/**
* JComboBoxcellrenderer.
*/
private DefaultListCellRenderer listCellRenderer = new DefaultListCellRenderer()
{
private static final long serialVersionUID = -7330621790373229915L;
// 重写它的方法:
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus)
{
if (value == null)
{
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
list.setToolTipText(value.toString());
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
};
protected transient KeyListener keyListener = new KeyAdapter()
{
@Override
public void keyPressed(final KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_F4)
{
FilterableComboBox.this.setPopupVisible(!FilterableComboBox.this.isPopupVisible());
FilterableComboBox.this.text.selectAll();
return;
}
if (FilterableComboBox.this.freezeFilter)
{
return;
}
Object item = FilterableComboBox.this.cmbModel.getSelectedItem();
if ((e.getKeyCode() == KeyEvent.VK_ENTER) || (e.getKeyCode() == KeyEvent.VK_TAB))
{
FilterableComboBox.this.changeSelect(item);
if (FilterableComboBox.this.filteredItems.size() == 0)
{
FilterableComboBox.this.reloadComboBox();
}
}
}
@Override
public void keyReleased(final KeyEvent e)
{
if ((e.getKeyCode() == KeyEvent.VK_ENTER) && (FilterableComboBox.this.cmbModel.getSelectedItem() == null))
{
try
{
FilterableComboBox.this.setPopupVisible(true);
}
catch (Exception ex)
{
}
}
}
};
protected DocumentListener documentListener = new DocumentListener()
{
@Override
public void changedUpdate(final DocumentEvent e)
{
}
@Override
public void insertUpdate(final DocumentEvent e)
{
try
{
FilterableComboBox.this.handleChange();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void removeUpdate(final DocumentEvent e)
{
try
{
FilterableComboBox.this.handleChange();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
};
private String orginStr = null;
private final ItemListener itemListener = new ItemListener()
{
@Override
public void itemStateChanged(final ItemEvent e)
{
if (e.getStateChange() == ItemEvent.SELECTED)
{
FilterableComboBox.this.fireActionPerformed();
}
}
};
public FilterableComboBox()
{
this.init();
this.setEditable(true);
}
// @Override
// public boolean requestFocus(boolean temporary)
// {
// super.requestFocus(temporary);
// this.text.selectAll();
// return this.text.requestFocus(temporary);
// }
//
// @Override
// public boolean requestFocusInWindow(boolean temporary)
// {
// super.requestFocusInWindow(temporary);
// this.text.selectAll();
// return this.text.requestFocus(temporary);
// }
//
// @Override
// public void requestFocus()
// {
// super.requestFocus();
// this.text.requestFocus();
// this.text.selectAll();
// }
//
// @Override
// public boolean requestFocusInWindow()
// {
// super.requestFocusInWindow();
// this.text.selectAll();
// return this.text.requestFocusInWindow();
// }
public FilterableComboBox(final BasicComboBoxEditor editor)
{
this.setModel(this.cmbModel);
this.cmbEditor = editor;
this.text = (JTextField) this.cmbEditor.getEditorComponent();
// this.text.setBorder(BorderFactory.createEmptyBorder());
this.text.addFocusListener(this.focusListener);
this.addKeyListener(this.keyListener);
this.text.addKeyListener(this.keyListener);
this.text.getDocument().addDocumentListener(this.documentListener);
this.setEditor(this.cmbEditor);
this.setRenderer(this.listCellRenderer);
this.setEditable(true);
}
public FilterableComboBox(final List<T> items)
{
this.init();
this.addItems(items);
this.setEditable(true);
this.isInitialed = true;
}
public FilterableComboBox(final T[] items)
{
this.init();
this.addItems(items);
this.setEditable(true);
this.isInitialed = true;
}
@Override
public void addActionListener(final ActionListener l)
{
if (!this.freezeFilter && !this.bItemListenerAdded)
{
this.addItemListener(this.itemListener);
this.bItemListenerAdded = true;
}
super.addActionListener(l);
}
/**
* @see javax.swing.JComboBox#addItem(java.lang.Object)
*/
@Override
public void addItem(final Object item)
{
this.addItem(item, false);
}
public void addItem(final Object item, final boolean isCheck)
{
if (isCheck)
{
if (!this.allItems.contains(item))
{
this.cmbModel.addElement(item);
}
}
else
{
this.cmbModel.addElement(item);
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
public void addItems(final Collection<T> items)
{
this.addItems(items, false);
}
public void addItems(final Collection<T> items, final boolean isCheck)
{
if ((items == null) || (items.size() == 0))
{
return;
}
if (isCheck)
{
for (T tmp : items)
{
if (!this.allItems.contains(tmp))
{
this.cmbModel.addElement(tmp);
}
}
}
else
{
this.cmbModel.addElementList(items);
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
public void addItems(final T[] items)
{
this.addItems(items, false);
}
public void addItems(final T[] items, final boolean isCheck)
{
if ((items == null) || (items.length == 0))
{
return;
}
if (isCheck)
{
for (T tmp : items)
{
if (!this.allItems.contains(tmp))
{
this.cmbModel.addElement(tmp);
}
}
}
else
{
for (Object tmp : items)
{
this.cmbModel.addElement(tmp);
}
}
if (this.isInitialed == false)
{
this.updateComboBox();
}
}
private void changeSelect(final Object item)
{
if (this.changed)
{
this.cmbEditor.setItem(item);
this.cmbModel.setSelectedItem(item);
this.oldItem = item;
this.changed = false;
}
}
@Override
public void fireActionEvent()
{
if (this.freezeFilter)
{
super.fireActionEvent();
}
}
private void fireActionPerformed()
{
super.fireActionEvent();
}
private void fixMaxVisibleItemCount()
{
if (this.filteredItems.size() < FilterableComboBox.MAXROWCOUNT)
{
this.setMaximumRowCount(this.filteredItems.size());
}
else
{
this.setMaximumRowCount(FilterableComboBox.MAXROWCOUNT);
}
}
/**
* 根据字符串查找出一个Item.<br/>
*
* @param filterStr
* @return T
*/
public T getFilterItem(final String filterStr)
{
Filter tmpFilter = new StartsWithFilter(filterStr);
for (T item : this.allItems)
{
if (tmpFilter.accept(item))
{
return item;
}
}
return null;
}
@Override
public T getSelectedItem()
{
return this.cmbModel.getSelectedItem();
}
protected void handleChange()
{
if (this.freezeFilter)
{
return;
}
if (this.setting)
{
return;
}
this.filtering = true;
Filter filter = null;
if (this.text.getText().length() > 0)
{
this.orginStr = this.text.getText();
filter = new StartsWithFilter(this.orginStr);
}
else
{
this.orginStr = null;
}
this.setFilter(filter);
// A bit nasty but it seems to get the popup validated properly
// setPopupVisible(false);
if (this.filteredItems.size() > 0)
{
this.setPopupVisible(true);
}
else
{
this.setPopupVisible(false);
}
this.filtering = false;
}
private void init()
{
this.setModel(this.cmbModel);
this.cmbEditor = new FilterableEditor();
this.setEditor(this.cmbEditor);
this.setRenderer(this.listCellRenderer);
this.addKeyListener(this.keyListener);
}
public boolean isInitialed()
{
return this.isInitialed;
}
private void reloadComboBox()
{
this.setting = true;
if (this.filteredItems.size() < this.allItems.size())
{
this.filteredItems.clear();
this.filteredItems.addAll(this.allItems);
this.updateComboBox();
}
this.setting = false;
}
@Override
public void removeAllItems()
{
super.removeAllItems();
this.filteredItems.clear();
this.allItems.clear();
}
@Override
public void removeItem(final Object item)
{
this.allItems.remove(item);
this.cmbModel.removeElement(item);
if (this.isInitialed == false)
{
this.fixMaxVisibleItemCount();
this.cmbModel.fireIntervalRemoved(this, 0, this.cmbModel.getSize() - 1);
}
}
@Override
public void removeItemAt(final int index)
{
if (index < 0)
{
return;
}
if (index >= this.cmbModel.getSize())
{
return;
}
Object item = this.cmbModel.getElementAt(index);
this.removeItem(item);
}
@Override
protected void selectedItemChanged()
{
if (this.freezeFilter || (this.filtering == false))
{
super.selectedItemChanged();
}
}
public void setDefaultItem(final T defaultItem)
{
this.defaultItem = defaultItem;
}
public void setAllowedMismatch(final boolean allowedMismatch)
{
this.allowedMismatch = allowedMismatch;
}
private void setFilter(final Filter filter)
{
this.filter = filter;
this.cmbModel.updateFilteredItems();
}
public void setIsInitialed(final boolean isInitialed)
{
this.isInitialed = isInitialed;
if (this.isInitialed)
{
this.updateComboBox();
}
}
private void updateComboBox()
{
this.fixMaxVisibleItemCount();
this.cmbModel.fireIntervalAdded(this, 0, this.filteredItems.size());
}
}
接下来举例详细说明怎么IP控件和下拉框结合起来放进表格。