How to sort items in listview in qml
-
Nice trick, but it will not work in the current form if the underlying model is dynamic (and that is what you need sorting for in the first place, otherwise you'd just use a static, pre-sorted model in the first place) and the sorting routine looks painfully slow. Not an issue if you need to sort a small list, but this will quickly start to be a performance hit I think.
-
Yes, you are right. I used it for just 20~30 items and the bubble sort method isn't efficient because the swap element is not supported, but sort function could/should be reimplemented.
If the model is dynamic something like this could be of some help ?@ Timer {
id: waitTimer
interval: 50
repeat: false
triggeredOnStart: false
running: false
onTriggered: { fillListModel(); sortModel(); }
}ListModel { id: listModelToSort onItemsInserted: waitTimer.restart() }@
-
Hallo, I was looking for soemthing really similar. I tried it but I am gettin error. could not rectify it. Kindly help me out!
@import QtQuick 1.1
//import "check.js" as ChkRectangle{
width:400
height:widthComponent.onCompleted: { sortModel(); fillListModel();}
function sortModel()
{
var n;
var i;
for (n=0; n < grdview.count; n++)
for (i=n+1; i < grdview.count; i++)
{
if (grdview.model.get(n).id> grdview.model.get(i).id)
{
// console.log("checking for the id ")
// console.log(grdview.model.get(n).title)
grdview.model.move(i, n, 1);
n=0;
}
}}function fillListModel() { var n; for (n=0; n < xmlModel.count; n++) { console.log(xmlModel.count) console.log("Sfasd") listModel.append({"title": xmlModel.get(n).title, "pubDate":xmlModel.get(n).pubDate, "id":xmlModel.get(n).id}) }}
XmlListModel {
id: xmlModel
source: "example.xml"
query: "/rss/channel/item"
XmlRole { name: "id"; query: "id/string()" }
XmlRole { name: "title"; query: "title/string()" }
XmlRole { name: "pubDate"; query: "pubDate/string()" }
onStatusChanged: if (status === XmlListModel.Ready) {sortModel();fillListModel(); }
}GridView{
id:grdview
width: 180; height: 300
model:xmlModel
delegate: Text { text:title+ ": " + pubDate+id
}
visible:false}
ListModel {
id: listModel}
ListView{model:listModel
width: 180; height: 300
delegate: Text { text:title+ ": " + pubDate+id}}
}
@and the error i get is :TypeError: Result of expression 'grdview.model.move' [undefined] is not a function. kindly let me know what is the mistake. I can also send u the xml file if required.
-
@<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
...
<channel>
<item>
<title>A blog post</title>
<pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
<id> 3 </id>
</item>
<item>
<title>A blog post</title>
<pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
<id> 4 </id>
</item>
<item>
<title>A blog post</title>
<pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
<id> 2 </id> </item>
<item>
<title>A blog post</title>
<pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
<id> 1 </id>
</item>
<item>
<title>Another blog post</title>
<pubDate>Sat, 07 Sep 2010 15:35:01 GMT</pubDate>
<id> 0 </id>
</item>
</channel>
</rss>@This is the xml file am using
-
Hi,
I found something wrong in you code: the dummy model listModel should be filled before sorting it and gridView model is a XmlModelList that is read only, so in the sort function you can't move elements.
I come into this implementation and added also a listModel.clear(); in the fillListModel() function because if the xml model get updated, the new reads will be appended to the already filled model.regards
@import QtQuick 1.1
//import "check.js" as ChkRectangle{
width:400 height:width function sortModel() { var n; var i; for (n=0; n < listModel.count; n++) for (i=n+1; i < listModel.count; i++) { if (listModel.get(n).id> listModel.get(i).id) { listModel.move(i, n, 1); n=0; } } } function fillListModel() { var n; listModel.clear(); for (n=0; n < xmlModel.count; n++) { listModel.append({"title": xmlModel.get(n).title, "pubDate":xmlModel.get(n).pubDate, "id":xmlModel.get(n).id}) } } XmlListModel { id: xmlModel source: "example.xml" query: "/rss/channel/item" XmlRole { name: "id"; query: "id/string()" } XmlRole { name: "title"; query: "title/string()" } XmlRole { name: "pubDate"; query: "pubDate/string()" } onStatusChanged: if (status === XmlListModel.Ready) { console.log("xml read: ", count); fillListModel(); sortModel(); } } GridView{ id:grdview width: 180; height: 300 model: xmlModel delegate: Text { text:title+ ": " + pubDate+id } visible:false } ListModel { id: listModel } ListView{ model:listModel width: 180; height: 300 delegate: Text { text:title+ ": " + pubDate+id} }
}@
-
In my projetc i add the quick sort algorythm to ListModel.
It works pretty well.
Save this code into a qml file , for example SortListModel.qml
and use @SortListModel.sortColumnName="productName";
SortListModel.quick_sort();@@import QtQuick 2.0
ListModel {
property string sortColumnName: "" id: sortlistmodel function swap(a,b) { if (a<b) { move(a,b,1); move (b-1,a,1); } else if (a>b) { move(b,a,1); move (a-1,b,1); } } function partition(begin, end, pivot) { var piv=get(pivot)[sortColumnName]; swap(pivot, end-1); var store=begin; var ix; for(ix=begin; ix<end-1; ++ix) { if(get(ix)[sortColumnName] < piv) { swap(store,ix); ++store; } } swap(end-1, store); return store; } function qsort(begin, end) { if(end-1>begin) { var pivot=begin+Math.floor(Math.random()*(end-begin)); pivot=partition( begin, end, pivot); qsort(begin, pivot); qsort(pivot+1, end); } } function quick_sort() { qsort(0,count) }
}@
-
@remy67 I know it's been a long time, but thank you!! I was able to use this and it was very helpful
I added a sort order argument as well (super easy with your setup)
import QtQuick 2.0
ListModel {
property string sortColumnName: "" property string order: "desc" //set to either asc or desc id: sortlistmodel function swap(a,b) { if (a<b) { move(a,b,1); move (b-1,a,1); } else if (a>b) { move(b,a,1); move (a-1,b,1); } } function partition(begin, end, pivot) { var piv=get(pivot)[sortColumnName]; swap(pivot, end-1); var store=begin; var ix; for(ix=begin; ix<end-1; ++ix) { if (order ==="asc"){ if(get(ix)[sortColumnName] < piv) { swap(store,ix); ++store; } }else if (order ==="desc"){ if(get(ix)[sortColumnName] > piv) { swap(store,ix); ++store; } } } swap(end-1, store); return store; } function qsort(begin, end) { if(end-1>begin) { var pivot=begin+Math.floor(Math.random()*(end-begin)); pivot=partition( begin, end, pivot); qsort(begin, pivot); qsort(pivot+1, end); } } function quick_sort() { qsort(0,count) }
}
-
We can make use of Array.prototype.sort():
- Create an array of indexes the same size of the listModel
- Use Array.prototype.sort() to rearrange the index with an appropriately written compareFunc
- Then rearrange the listModel as per the new order of items as shown in the index
Here's the QML ListModel sort function:
function listModelSort(listModel, compareFunc) { var indexes = new Array(listModel.count); for (var i = 0; i < listModel.count; i++) indexes[i] = i; indexes.sort(function (indexA, indexB) { return compareFunc(get(indexA), get(indexB)) } ); var sorted = 0; while (sorted < indexes.length && sorted === indexes[sorted]) sorted++; if (sorted === indexes.length) return; for (i = sorted; i < indexes.length; i++) { var idx = indexes[i]; listModel.move(idx, listModel.count - 1, 1); listModel.insert(idx, { } ); } listModel.remove(sorted, indexes.length - sorted); }
See Also:
- my full GIST code snippet: https://gist.github.com/stephenquan/fcad6ecd4b28051c61cf48853e39c9e4
- related StackOverflow post: https://stackoverflow.com/questions/29429710/how-to-auto-sort-qml-listelements-in-sections