Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to sort items in listview in qml
Forum Updated to NodeBB v4.3 + New Features

How to sort items in listview in qml

Scheduled Pinned Locked Moved QML and Qt Quick
13 Posts 7 Posters 36.0k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    rashid.inayat
    wrote on 28 Oct 2011, 08:41 last edited by
    #1

    Hello Guys!

    I want to know how could I sort items in a listview populated from locally available data in local db in list model.
    BTW I cannot sort on sqlite query since after loading data from db I need to make some changes in for example replace "Book Of" with " ". So after that I need to sort my data but not in sql query.

    So simply if you have a populated listview in qml how could we sort its contents alphabetically?

    Thank You

    1 Reply Last reply
    0
    • A Offline
      A Offline
      andre
      wrote on 28 Oct 2011, 08:52 last edited by
      #2

      Sorry, AFAIK, this is not (yet) possible to do in pure QML. Instead, you could create your model from C++ and use a [[doc:QSortFilterProxyModel]] to do the sorting, and then expose that model to your QML.

      1 Reply Last reply
      0
      • D Offline
        D Offline
        deimos
        wrote on 28 Oct 2011, 11:17 last edited by
        #3

        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&lt; 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
        }@
        
        1 Reply Last reply
        0
        • A Offline
          A Offline
          andre
          wrote on 28 Oct 2011, 11:24 last edited by
          #4

          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.

          1 Reply Last reply
          0
          • D Offline
            D Offline
            deimos
            wrote on 28 Oct 2011, 13:30 last edited by
            #5

            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()
            }@
            
            1 Reply Last reply
            0
            • J Offline
              J Offline
              Julie1986
              wrote on 4 Sept 2012, 13:47 last edited by
              #6

              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 Chk

              Rectangle{

              width:400
              height:width

              Component.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 &lt; 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.

              1 Reply Last reply
              0
              • J Offline
                J Offline
                Julie1986
                wrote on 4 Sept 2012, 13:49 last edited by
                #7

                @<?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

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  deimos
                  wrote on 4 Sept 2012, 16:29 last edited by
                  #8

                  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 Chk

                  Rectangle{

                  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 &lt; 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}
                  }
                  

                  }@

                  1 Reply Last reply
                  0
                  • J Offline
                    J Offline
                    Julie1986
                    wrote on 5 Sept 2012, 07:42 last edited by
                    #9

                    Hey, thanks you. works great.. I appreciate it. [Solved]

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      deimos
                      wrote on 5 Sept 2012, 09:50 last edited by
                      #10

                      Your welcome, but remember what Andre wrote:

                      bq. 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.

                      regards

                      1 Reply Last reply
                      0
                      • R Offline
                        R Offline
                        remy67
                        wrote on 11 Oct 2014, 17:22 last edited by
                        #11

                        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)
                        }
                        

                        }@

                        T 1 Reply Last reply 28 Mar 2015, 22:53
                        2
                        • R remy67
                          11 Oct 2014, 17:22

                          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)
                          }
                          

                          }@

                          T Offline
                          T Offline
                          tunahammer
                          wrote on 28 Mar 2015, 22:53 last edited by
                          #12

                          @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)
                          }
                          

                          }

                          hammering tuna

                          1 Reply Last reply
                          1
                          • S Offline
                            S Offline
                            Stephen Quan
                            wrote on 18 Feb 2019, 23:49 last edited by Stephen Quan
                            #13

                            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
                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved