“我认为过滤它显示的内容是视图的责任” - 我认为,视图显示它所告诉的内容,模型驱动它可以显示的内容,但这就是我.. .
这是我在 Java 1.3(带有通用更新)中写的一个想法,它基本上将代理 ComboBoxModel 包裹在另一个 ComboBoxModel 周围。然后代理(或FilterableComboBoxModel)决定原始模型中的哪些元素与过滤器匹配并更新它的索引。
基本上,它所做的只是在自己和原始模型之间生成一个索引映射,因此它不会复制任何内容或生成对原始数据的新引用。
过滤是通过“可过滤”接口控制的,该接口简单地传递要检查的元素并期望boolean作为响应结果。这使得 API 非常灵活,因为过滤可以按照您想要的任何方式完成,而无需以任何方式更改 FilterableComboBoxModel。这也意味着您可以通过简单地应用一个新的过滤器来更改使用的过滤器......
如果像我通常做的那样,你想向过滤器传递一些值,你需要通过updateFilter 方法通知模型过滤器已更改...是的,我知道,@987654328 @ 可能是一个更好的主意,但我试图保持简单;)
为了灵活性(并维护当前的继承模型),核心 API 基于 ListModel,这意味着,您也可以将相同的概念与 JList 一起使用
FilterableListModel
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
public class FilterableListModel<E> extends AbstractListModel<E> implements ListDataListener {
private ListModel<E> peer;
private List<Integer> lstFilteredIndicies;
private IFilterable filter;
public FilterableListModel() {
lstFilteredIndicies = new ArrayList<Integer>(25);
}
public FilterableListModel(ListModel<E> model) {
this();
setModel(model);
}
public FilterableListModel(ListModel<E> model, IFilterable filter) {
this();
setModel(model);
setFilter(filter);
}
public void setModel(ListModel<E> parent) {
if (peer == null || !peer.equals(parent)) {
if (peer != null) {
fireIntervalRemoved(this, 0, peer.getSize() - 1);
peer.removeListDataListener(this);
}
peer = parent;
lstFilteredIndicies.clear();
if (peer != null) {
peer.addListDataListener(this);
}
filterModel(true);
}
}
public ListModel<E> getModel() {
return peer;
}
@Override
public int getSize() {
IFilterable filter = getFilter();
return filter == null ? getModel() == null ? 0 : getModel().getSize() : lstFilteredIndicies.size();
}
@Override
public E getElementAt(int index) {
IFilterable filter = getFilter();
ListModel<E> model = getModel();
E value = null;
if (filter == null) {
if (model != null) {
value = model.getElementAt(index);
}
} else {
int filterIndex = lstFilteredIndicies.get(index);
value = model.getElementAt(filterIndex);
}
return value;
}
public int indexOf(Object value) {
int index = -1;
for (int loop = 0; loop < getSize(); loop++) {
Object at = getElementAt(loop);
if (at == value) {
index = loop;
break;
}
}
return index;
}
@Override
public void intervalAdded(ListDataEvent e) {
IFilterable filter = getFilter();
ListModel model = getModel();
if (model != null) {
if (filter != null) {
int startIndex = Math.min(e.getIndex0(), e.getIndex1());
int endIndex = Math.max(e.getIndex0(), e.getIndex1());
for (int index = startIndex; index <= endIndex; index++) {
Object value = model.getElementAt(index);
if (filter.include(value)) {
lstFilteredIndicies.add(index);
int modelIndex = lstFilteredIndicies.indexOf(index);
fireIntervalAdded(this, modelIndex, modelIndex);
}
}
} else {
fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
}
}
}
@Override
public void intervalRemoved(ListDataEvent e) {
IFilterable filter = getFilter();
ListModel model = getModel();
if (model != null) {
if (filter != null) {
int oldRange = lstFilteredIndicies.size();
filterModel(false);
fireIntervalRemoved(this, 0, oldRange);
if (lstFilteredIndicies.size() > 0) {
fireIntervalAdded(this, 0, lstFilteredIndicies.size());
}
} else {
fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
}
}
}
@Override
public void contentsChanged(ListDataEvent e) {
filterModel(true);
}
public void setFilter(IFilterable<E> value) {
if (filter == null || !filter.equals(value)) {
filter = value;
if (getModel() != null) {
if (getModel().getSize() > 0) {
fireIntervalRemoved(this, 0, getModel().getSize() - 1);
}
}
filterModel(true);
}
}
public IFilterable<E> getFilter() {
return filter;
}
protected void filterModel(boolean fireEvent) {
if (getSize() > 0 && fireEvent) {
fireIntervalRemoved(this, 0, getSize() - 1);
}
lstFilteredIndicies.clear();
IFilterable<E> filter = getFilter();
ListModel<E> model = getModel();
if (filter != null && model != null) {
for (int index = 0; index < model.getSize(); index++) {
E value = model.getElementAt(index);
if (filter.include(value)) {
lstFilteredIndicies.add(index);
if (fireEvent) {
fireIntervalAdded(this, getSize() - 1, getSize() - 1);
}
}
}
}
}
public void updateFilter() {
IFilterable filter = getFilter();
ListModel model = getModel();
if (filter != null && model != null) {
for (int index = 0; index < model.getSize(); index++) {
Object value = model.getElementAt(index);
if (filter.include(value)) {
if (!lstFilteredIndicies.contains(index)) {
lstFilteredIndicies.add(index);
fireIntervalAdded(this, getSize() - 1, getSize() - 1);
}
} else if (lstFilteredIndicies.contains(index)) {
int oldIndex = lstFilteredIndicies.indexOf(index);
lstFilteredIndicies.remove(oldIndex);
fireIntervalRemoved(this, oldIndex, oldIndex);
}
}
}
}
}
可过滤
public interface IFilterable<O> {
public boolean include(O value);
}
FilterableComboBoxModel
import javax.swing.ComboBoxModel;
public class FilterableComboBoxModel<E> extends FilterableListModel<E> implements ComboBoxModel<E> {
private FilterableComboBoxModel(ComboBoxModel<E> model) {
super(model);
}
public ComboBoxModel<E> getComboBoxModel() {
return (ComboBoxModel) getModel();
}
@Override
public void setSelectedItem(Object anItem) {
getComboBoxModel().setSelectedItem(anItem);
}
@Override
public Object getSelectedItem() {
return getComboBoxModel().getSelectedItem();
}
}
应该注意的是,实际上可以使用 RowFilter 代替,但我从来没有真正有时间查看它(因为我已经有一个可用的 API)