QML 动态视图排序教程 4 - 项目排序
拖放并不是视图中项目重新排序的唯一方法,使用DelegateModel 还可以根据模型数据对项目进行排序。为此,我们可以像这样扩展DelegateModel 实例:
DelegateModel { id: visualModel property var lessThan: [ function(left, right) { return left.name < right.name }, function(left, right) { return left.type < right.type }, function(left, right) { return left.age < right.age }, function(left, right) { if (left.size == "Small") return true else if (right.size == "Small") return false else if (left.size == "Medium") return true else return false } ] property int sortOrder: orderSelector.selectedIndex onSortOrderChanged: items.setGroups(0, items.count, "unsorted") function insertPosition(lessThan, item) { let lower = 0 let upper = items.count while (lower < upper) { const middle = Math.floor(lower + (upper - lower) / 2) const result = lessThan(item.model, items.get(middle).model) if (result) { upper = middle } else { lower = middle + 1 } } return lower } function sort(lessThan) { while (unsortedItems.count > 0) { const item = unsortedItems.get(0) const index = insertPosition(lessThan, item) item.groups = "items" items.move(item.itemsIndex, index) } } items.includeByDefault: false groups: DelegateModelGroup { id: unsortedItems name: "unsorted" includeByDefault: true onChanged: { if (visualModel.sortOrder == visualModel.lessThan.length) setGroups(0, count, "items") else visualModel.sort(visualModel.lessThan[visualModel.sortOrder]) } } model: PetsModel {} delegate: dragDelegate }
演练
DelegateModel 中的项目会被筛选到由DelegateModelGroup 类型表示的组中,通常模型中的所有项目都属于默认的items 组,但可以使用 includeByDefault 属性更改默认组。为了实现排序,我们希望首先将项目添加到未排序组中,然后再将其转移到项目组中的排序位置。为此,我们清除了项目组中的 includeByDefault 属性,并将其设置为一个名为 "unsorted "的新组。
items.includeByDefault: false groups: DelegateModelGroup { id: unsortedItems name: "unsorted" includeByDefault: true }
我们对项目进行排序的方法是,首先在项目组中找到插入第一个未排序项目的位置,然后将项目转移到项目组中,再将其移动到预先确定的索引中,如此重复,直到未排序组为空。
为了找到项目的插入位置,我们使用get() 函数从未分类组中请求一个项目句柄。通过该句柄上的模型属性,我们可以访问该项目委托实例中的相同模型数据,并与其他项目进行比较,以确定相对位置。
function insertPosition(lessThan, item) { let lower = 0 let upper = items.count while (lower < upper) { const middle = Math.floor(lower + (upper - lower) / 2) const result = lessThan(item.model, items.get(middle).model) if (result) { upper = middle } else { lower = middle + 1 } } return lower } function sort(lessThan) { while (unsortedItems.count > 0) { const item = unsortedItems.get(0) const index = insertPosition(lessThan, item) item.groups = "items" items.move(item.itemsIndex, index) } }
排序功能的 lessThan 参数是一个比较函数,它将决定列表的顺序。在本示例中,它可以是以下参数之一:
property var lessThan: [ function(left, right) { return left.name < right.name }, function(left, right) { return left.type < right.type }, function(left, right) { return left.age < right.age }, function(left, right) { if (left.size == "Small") return true else if (right.size == "Small") return false else if (left.size == "Medium") return true else return false } ]
每当有新项目添加到未排序的DelegateModel 时,就会触发排序,而DelegateModelGroup onChanged
处理程序会通知我们。如果当前未选择排序功能,我们只需将未排序组中的所有项目转移到项目组中,否则我们会调用已选择的排序功能进行排序。
groups: DelegateModelGroup { id: unsortedItems name: "unsorted" includeByDefault: true onChanged: { if (visualModel.sortOrder == visualModel.lessThan.length) setGroups(0, count, "items") else visualModel.sort(visualModel.lessThan[visualModel.sortOrder]) } }
最后,当所选的排序顺序发生变化时,我们可以通过将所有项目从项目组移至未排序组来触发对列表的全面重新排序,这将触发DelegateModelGroup onChanged
处理程序,并将项目按正确顺序移回项目组。请注意,DelegateModelGroup onChanged
处理程序不会被递归调用,因此在排序过程中调用它不会有问题。
property int sortOrder: orderSelector.selectedIndex onSortOrderChanged: items.setGroups(0, items.count, "unsorted")
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.