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
}我们对项目进行排序的步骤是:首先在“items”组中找到插入第一个未排序项目的位置,然后将该项目转移到“items”组中,再将其移动到预先确定的索引位置,并重复此过程直至“未排序”组为空。
要查找项目的插入位置,我们使用get()函数从“未排序”组中获取该项目的句柄。通过该句柄的model属性,我们可以访问与该项目的委托实例中相同的模型数据,并与其他项目进行比较以确定相对位置。
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])
}
}最后,当选定的排序顺序发生变化时,我们可以将“items”组中的所有项目移至“un sorted”组,从而触发列表的全面重新排序;此操作将触发DelegateModelGroup onChanged 处理程序,并将项目按正确顺序移回“items”组。 请注意,DelegateModelGroup onChanged 处理程序不会被递归调用,因此在排序过程中调用它不会产生问题。
property int sortOrder: orderSelector.selectedIndex
onSortOrderChanged: items.setGroups(0, items.count, "unsorted")© 2026 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.