How to sort items in listview in qml
-
What Andre said is right and probably the best way. I tried another solution that works, but this implies a little more resources and a custom sort function.
When the component is completed you can fill another ListModel with sorted elements of your first one and use it.
I used a XmlListModel here, but the concept is the same.
buttonsGridView is the GridView and you can fill listModel by:@Component:onCompleted: { fillListModel(); sortModel(); }@
here there is what I did:
@function sortModel()
{
var n;
var i;
for (n=0; n < buttonsGridView.count; n++)
for (i=n+1; i < buttonsGridView.count; i++)
{
if (buttonsGridView.model.get(n).nameCat > buttonsGridView.model.get(i).nameCat)
{
buttonsGridView.model.move(i, n, 1);
n=0; // Repeat at start since I can't swap items i and n
}
}
}// Use a ListModel to sort out the list function fillListModel() { var n; for (n=0; n< xmlModel.count; n++) listModel.append({"idCat": xmlModel.get(n).idCat, "nameCat": xmlModel.get(n).nameCat}) } XmlListModel { id: xmlModel source: ... query: ... XmlRole { name: "idCat"; query: "id/string()" } XmlRole { name: "nameCat"; query: "name/string()" } onStatusChanged: if (status === XmlListModel.Ready) { fillListModel(); sortModel(); } } ListModel { id: listModel }@
-
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