ZK 7.0.3 ListBox多列排序及排序图标保持方法问询
嘿,我刚好在ZK 7.0.3里处理过类似的多列排序需求,结合表头图标持久显示的问题,给你一步步拆解怎么实现:
一、实现按第一列、第二列依次的多列排序
ZK的ListBox默认只支持单列排序,多列排序需要我们自己维护排序规则和逻辑,核心思路是监听表头点击事件,记录排序列的顺序和升降序状态,然后手动对列表数据进行排序。
1. 先写ZUL页面的ListBox结构
给每个表头绑定点击事件,传递对应的列名,同时开启sort="auto"来让表头默认有排序图标(后续我们会手动控制图标状态):
<listbox id="myListbox" model="@load(vm.itemList)"> <listhead> <!-- 给表头加id方便后续获取,传递列名col1 --> <listheader id="col1Header" label="第一列" sort="auto" onClick="@command('sortColumn', col='col1')" /> <listheader id="col2Header" label="第二列" sort="auto" onClick="@command('sortColumn', col='col2')" /> <!-- 其他列按需添加 --> </listhead> <listitem self="@{each=item}"> <listcell label="@load(item.col1)" /> <listcell label="@load(item.col2)" /> </listitem> </listbox>
2. 在ViewModel里维护排序状态
定义两个变量来记录排序的列顺序和每列的升降序:
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.zkoss.bind.annotation.BindingParam; import org.zkoss.bind.annotation.Command; import org.zkoss.zk.ui.Executions; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listheader; import org.zkoss.zul.Listhead; import org.zkoss.zul.SortDirection; // 假设你的ViewModel类是这样的 public class MyViewModel { // 存储排序列的顺序,第一个是主排序列,第二个是次排序列 private List<String> sortColumns = new ArrayList<>(); // 存储每列的升降序状态,key是列名,value是"asc"或"desc" private Map<String, String> sortOrders = new HashMap<>(); // 你的列表数据,假设Item是你的数据实体类 private List<Item> itemList; // 初始化数据的方法,这里省略...
3. 处理表头点击事件,执行排序
写一个sortColumn命令来处理点击逻辑,维护排序状态并触发排序:
@Command public void sortColumn(@BindingParam("col") String col) { // 如果点击的列已经在排序列表里,切换它的升降序 if (sortColumns.contains(col)) { String currentOrder = sortOrders.get(col); sortOrders.put(col, "asc".equals(currentOrder) ? "desc" : "asc"); } else { // 如果是新列,添加到排序列表,默认升序 sortColumns.add(col); sortOrders.put(col, "asc"); // 只保留最多两列排序(符合需求:按第一、第二列依次排) if (sortColumns.size() > 2) { sortColumns.remove(0); } } // 执行列表排序 sortItemList(); // 更新表头的排序图标 updateHeaderSortIcons(); }
4. 实现多列排序的核心逻辑
编写sortItemList方法,根据我们维护的排序规则对列表进行排序:
private void sortItemList() { Collections.sort(itemList, new Comparator<Item>() { @Override public int compare(Item o1, Item o2) { // 先按第一排序列比较 String firstCol = sortColumns.get(0); int firstCompare = compareByColumn(o1, o2, firstCol); // 如果第一列有差异,直接返回结果,注意升降序 if (firstCompare != 0) { return "asc".equals(sortOrders.get(firstCol)) ? firstCompare : -firstCompare; } // 如果第一列相同,再按第二列比较(如果存在第二排序列) if (sortColumns.size() >= 2) { String secondCol = sortColumns.get(1); int secondCompare = compareByColumn(o1, o2, secondCol); return "asc".equals(sortOrders.get(secondCol)) ? secondCompare : -secondCompare; } return 0; } // 根据列名获取属性值并比较,这里假设是字符串类型,你可以根据实际类型调整 private int compareByColumn(Item o1, Item o2, String col) { String val1 = getPropertyValue(o1, col); String val2 = getPropertyValue(o2, col); return val1.compareTo(val2); } // 映射列名到实体类的属性 private String getPropertyValue(Item item, String col) { if ("col1".equals(col)) { return item.getCol1(); } else if ("col2".equals(col)) { return item.getCol2(); } return ""; } }); // 通知ZK更新视图 org.zkoss.bind.BindUtils.postNotifyChange(null, null, this, "itemList"); }
注意:如果你的数据是数字、日期类型,要把
compareByColumn里的比较逻辑改成对应类型的比较,比如转成Integer或者LocalDate来比较。
二、让表头排序图标保持显示
ZK默认只会给当前“活跃”的排序列显示图标,其他列会清空图标。我们需要手动控制每个表头的sortDirection属性,让参与排序的列一直显示对应的图标。
实现updateHeaderSortIcons方法:
private void updateHeaderSortIcons() { // 获取页面上的ListBox组件 Listbox listbox = (Listbox) Executions.getCurrent().getDesktop().getComponentById("myListbox"); Listhead listhead = listbox.getListhead(); // 遍历所有表头,设置对应的排序图标 for (Listheader header : listhead.getListheaders()) { String colName = getColNameFromHeader(header); if (sortColumns.contains(colName)) { // 如果是排序列,设置对应的升降序图标 String order = sortOrders.get(colName); header.setSortDirection("asc".equals(order) ? SortDirection.ASCENDING : SortDirection.DESCENDING); } else { // 非排序列,清空图标 header.setSortDirection(SortDirection.NONE); } } } // 根据表头id映射到列名 private String getColNameFromHeader(Listheader header) { if ("col1Header".equals(header.getId())) { return "col1"; } else if ("col2Header".equals(header.getId())) { return "col2"; } return ""; }
这样每次排序后,所有参与排序的表头都会保留对应的升序/降序图标,直到你再次点击切换状态或者该列被移出排序列表。
额外小提示
- 如果你的列表用的是
ListModelList,可以直接调用listModelList.sort(comparator),这样不需要手动调用postNotifyChange,ZK会自动更新视图。 - 对于复杂的实体类属性,建议用反射或者Apache BeanUtils来获取属性值,减少硬编码的工作量。
内容的提问来源于stack exchange,提问作者hephestos
相关产品推荐
相关产品推荐

