这里说的“可搜索的ComboBox”,是在基本的combobox基础上,增加搜索的功能,随着用户输入内容的变化,过滤下拉选框中的内容。
首先需要明确的问题是:下拉选框中的内容是固定的,还是会发生变化?换句话说,选项是本地固定写好的,还是要从服务端(数据库,webservice等)读取的?
情况一:选项是本地写好的。固定的选项。这是相对简单的一种情况。这种情况下有两种实现方式:
实现A:使用SuggestBox。
MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
oracle.add("Cat");
oracle.add("Dog");
oracle.add("Horse");
oracle.add("Canary");
SuggestBox box = new SuggestBox(oracle);
效果是这样的:
SuggestBox的API见这里
实现B:在store上加storeFilter
步骤:1-创建StoreFilterField的实例,重写doSelect方法
2-将Store
StoreFilterField<ModelData> filterField = new StoreFilterField<ModelData>() {
@Override
protected boolean doSelect(Store<ModelData> store, ModelData parent, ModelData record, String property, String filter) {
String name = record.get("key").toString();
name = name.toLowerCase();
if (name.startsWith(filter.toLowerCase())) {
return true;
}
return false;
}
};
ComboBox<ModelData> daysBox = new ComboBox<ModelData>();
ListStore<ModelData> store = new ListStore<ModelData>();
store.add(getDateRage());
daysBox.setStore(store);
daysBox.setDisplayField("key");
filterField.bind(store);
private List<ModelData> getDateRage() {
List<ModelData> list = new ArrayList<ModelData>();
list = new ArrayList<ModelData>();
ModelData bm = new BaseModelData();
bm.set("value", "1");
// bm.set("key", "1 day");
bm.set("key", "1");
list.add(bm);
bm = new BaseModelData();
bm.set("value", "2");
// bm.set("key", "2 days");
bm.set("key", "2");
list.add(bm);
bm = new BaseModelData();
bm.set("value", "10");
// bm.set("key", "10 days");
bm.set("key", "10");
list.add(bm);
bm = new BaseModelData();
bm.set("value", "30");
// bm.set("key", "30 days");
bm.set("key", "30");
list.add(bm);
bm = new BaseModelData();
bm.set("value", "90");
// bm.set("key", "90 days");
bm.set("key", "90");
list.add(bm);
bm = new BaseModelData();
bm.set("value", "All");
bm.set("key", "All");
list.add(bm);
return list;
}
很简单。还有一种实现方法和这个类似,具体参考文章末尾相关链接的第三条链接。
实现:需要在服务器端做过滤。涉及到三个类:
ListStore 下拉框的备选项集合
ListLoader 数据源的loader
RpcProxy Rpc代理对象,用于和服务器进行交互
先解释一下loader自动加载选项的原理:
1. 在下拉框中敲下3个及以上字符,触发loader的load方法。
2. loader使用proxy来加载数据。
3. proxy被执行,service方法被调用,和服务器进行交互。
4. RpcProxy返回数据加载进loader,触发loader的load event
5. store监听loader的event,从而添加新的数据。
实现的代码为:
import java.util.List;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
public abstract class QueryableComboBox<T> extends ComboBox<ModelData> {
private static final int MIN_INPUT_CHAR = 3;//输入3个或3个以上字符触发loader的load方法
protected RpcProxy<List<T>> proxy;
public QueryableComboBox() {
super();
init();
}
protected void init() {
initLoader();
ListStore<ModelData> store = new ListStore<ModelData>(initLoader());
setStore(store);
setMinChars(MIN_INPUT_CHAR);
setTypeAhead(true);//
setTriggerAction(TriggerAction.ALL);
setAllowBlank(false);
setForceSelection(true);
setEditable(true);
setUseQueryCache(false);
}
protected ListLoader<ListLoadResult<ModelData>> initLoader() {
proxy = initProxy();
ListLoader<ListLoadResult<ModelData>> loader = new BaseListLoader<ListLoadResult<ModelData>>(proxy, new BeanModelReader()) {
@Override
protected Object newLoadConfig() {
return new BasePagingLoadConfig();
}
};
return loader;
}
public void setValueRapidly(ModelData md) {
getStore().removeAll();
getStore().add(md);
setValue(md);
lastQuery = (String) md.get(getDisplayField());
}
public abstract RpcProxy<List<T>> initProxy();
}
使用的时候实现一下initProxy方法就可以了。
总结:gwt中实现各种形式的filter功能时,都要先考虑一下,是本地的filter还是远程的filter?之后具体问题具体分析。呵呵。
一些相关链接:
stackoverflow: combobox auto-complete
Change default behaivior of typeAhead in a Ext-Gwt Combobox