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处理程序通知。如果没有当前选择排序函数,我们只需将未排序组中的所有项目移动到项目组中,否则我们使用所选排序函数调用sort。
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")
© 2024 The Qt Company Ltd. 本文档中的贡献内容为各自所有者的版权。本文档依据由自由软件基金会发布的GNU自由文档许可证第1.3版许可条款提供。Qt及其相关标志是芬兰及/或其他国家/地区的The Qt Company Ltd.的商标。所有其他商标均为各自所有者的财产。