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 group items?
Forum Updated to NodeBB v4.3 + New Features

How to group items?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
17 Posts 2 Posters 2.1k Views 2 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.
  • fbg13F Offline
    fbg13F Offline
    fbg13
    wrote on last edited by
    #1

    Any ideas how to do something like in the screenshot below in qml?
    I have a list of songs and want to group them by album (or something else), with the album cover on the left and the songs on the right.

    The list is a QMap<int, Song*>

    #ifndef SONG_H
    #define SONG_H
    
    #include <QObject>
    
    class Song : public QObject
    {
        Q_OBJECT
    public:
        explicit Song(QObject *parent = nullptr);
    
        QString artist() const;
        void setArtist(const QString &artist);
    
        QString title() const;
        void setTitle(const QString &title);
    
        QString album() const;
        void setAlbum(const QString &album);
    
        QString disc() const;
        void setDisc(const QString &disc);
    
        QString year() const;
        void setYear(const QString &year);
    
        QString trackNumber() const;
        void setTrackNumber(const QString &trackNumber);
    
        QString length() const;
        void setLength(const QString &length);
    
    private:
        QString m_artist;
        QString m_title;
        QString m_album;
        QString m_disc;
        QString m_year;
        QString m_trackNumber;
        QString m_length;
    };
    
    #endif // SONG_H
    
    

    screenshot

    rrlopezR 1 Reply Last reply
    0
    • fbg13F fbg13

      Any ideas how to do something like in the screenshot below in qml?
      I have a list of songs and want to group them by album (or something else), with the album cover on the left and the songs on the right.

      The list is a QMap<int, Song*>

      #ifndef SONG_H
      #define SONG_H
      
      #include <QObject>
      
      class Song : public QObject
      {
          Q_OBJECT
      public:
          explicit Song(QObject *parent = nullptr);
      
          QString artist() const;
          void setArtist(const QString &artist);
      
          QString title() const;
          void setTitle(const QString &title);
      
          QString album() const;
          void setAlbum(const QString &album);
      
          QString disc() const;
          void setDisc(const QString &disc);
      
          QString year() const;
          void setYear(const QString &year);
      
          QString trackNumber() const;
          void setTrackNumber(const QString &trackNumber);
      
          QString length() const;
          void setLength(const QString &length);
      
      private:
          QString m_artist;
          QString m_title;
          QString m_album;
          QString m_disc;
          QString m_year;
          QString m_trackNumber;
          QString m_length;
      };
      
      #endif // SONG_H
      
      

      screenshot

      rrlopezR Offline
      rrlopezR Offline
      rrlopez
      wrote on last edited by
      #2

      @fbg13 Hello, have you checked out QSortFilterProxyModel? With it you can sort and filter any model:
      https://doc.qt.io/qt-5/qsortfilterproxymodel.html
      You will have to add the songs to a model and access them from it:
      https://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html

      Lic-Ing. Rodrigo Lopez Gonzalez
      Embedded Software Engineer
      RidgeRun Engineering Ltd.
      www.ridgerun.com
      Email: rodrigo.lopez@ridgerun.com

      fbg13F 1 Reply Last reply
      0
      • rrlopezR rrlopez

        @fbg13 Hello, have you checked out QSortFilterProxyModel? With it you can sort and filter any model:
        https://doc.qt.io/qt-5/qsortfilterproxymodel.html
        You will have to add the songs to a model and access them from it:
        https://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html

        fbg13F Offline
        fbg13F Offline
        fbg13
        wrote on last edited by
        #3

        @rrlopez What I need help with is how to display the groups in qml.

        I managed to do it by changing my model to hold the groups only and each group will have the songs.
        And in qml I have a repeater for the groups and for each group a repeater for the songs.

        Here's a repo https://gitlab.com/g-fb/music-player-layout-example with what I managed so far.

        Don't know how good this approach is and I can't think of another way.

        rrlopezR 1 Reply Last reply
        0
        • fbg13F fbg13

          @rrlopez What I need help with is how to display the groups in qml.

          I managed to do it by changing my model to hold the groups only and each group will have the songs.
          And in qml I have a repeater for the groups and for each group a repeater for the songs.

          Here's a repo https://gitlab.com/g-fb/music-player-layout-example with what I managed so far.

          Don't know how good this approach is and I can't think of another way.

          rrlopezR Offline
          rrlopezR Offline
          rrlopez
          wrote on last edited by
          #4

          @fbg13 I would use a QAbstractProxyModel to act as a model of your table view and change the way you define stuff in your QML.
          Basically add a row on the model for each song you want to display (artist, songname, artist, etc) and then access these roles on QML as model.artist, model.songname, etc.
          As you'll be using a QAbstractProxyModel you will have access to its sorting and filtering methods, so you will be able to filter out songs on artist. You basically will have N items where N is the number of artists, and each item from N will have a different filter to show only songs related to the corresponding artist.

          Lic-Ing. Rodrigo Lopez Gonzalez
          Embedded Software Engineer
          RidgeRun Engineering Ltd.
          www.ridgerun.com
          Email: rodrigo.lopez@ridgerun.com

          fbg13F 1 Reply Last reply
          0
          • rrlopezR rrlopez

            @fbg13 I would use a QAbstractProxyModel to act as a model of your table view and change the way you define stuff in your QML.
            Basically add a row on the model for each song you want to display (artist, songname, artist, etc) and then access these roles on QML as model.artist, model.songname, etc.
            As you'll be using a QAbstractProxyModel you will have access to its sorting and filtering methods, so you will be able to filter out songs on artist. You basically will have N items where N is the number of artists, and each item from N will have a different filter to show only songs related to the corresponding artist.

            fbg13F Offline
            fbg13F Offline
            fbg13
            wrote on last edited by
            #5

            @rrlopez said in How to group items?:

            @fbg13 I would use a QAbstractProxyModel to act as a model of your table view and change the way you define stuff in your QML.
            Basically add a row on the model for each song you want to display (artist, songname, artist, etc) and then access these roles on QML as model.artist, model.songname, etc.

            You mean the data for the model should be:
            data {song1, song2, .... } instead of data {album1 {song1, song2 ...}, album2 {song1, song2 ...}, album3 {song1, song2 ...}}

            As you'll be using a QAbstractProxyModel you will have access to its sorting and filtering methods, so you will be able to filter out songs on artist. You basically will have N items where N is the number of artists, and each item from N will have a different filter to show only songs related to the corresponding artist.

            But I don't want to filter the results. I want to show all songs, but they should be grouped and all groups should be visible at the same time.
            Like in the screenshot, the red rectangles are the groups (image on left and songs on the right).

            I guess my problem is how to add the image, since it should be added only when the value on which the songs are grouped changes, and have the layout I want, image on left and songs on the right.

            rrlopezR 1 Reply Last reply
            0
            • fbg13F fbg13

              @rrlopez said in How to group items?:

              @fbg13 I would use a QAbstractProxyModel to act as a model of your table view and change the way you define stuff in your QML.
              Basically add a row on the model for each song you want to display (artist, songname, artist, etc) and then access these roles on QML as model.artist, model.songname, etc.

              You mean the data for the model should be:
              data {song1, song2, .... } instead of data {album1 {song1, song2 ...}, album2 {song1, song2 ...}, album3 {song1, song2 ...}}

              As you'll be using a QAbstractProxyModel you will have access to its sorting and filtering methods, so you will be able to filter out songs on artist. You basically will have N items where N is the number of artists, and each item from N will have a different filter to show only songs related to the corresponding artist.

              But I don't want to filter the results. I want to show all songs, but they should be grouped and all groups should be visible at the same time.
              Like in the screenshot, the red rectangles are the groups (image on left and songs on the right).

              I guess my problem is how to add the image, since it should be added only when the value on which the songs are grouped changes, and have the layout I want, image on left and songs on the right.

              rrlopezR Offline
              rrlopezR Offline
              rrlopez
              wrote on last edited by
              #6

              @fbg13 said in How to group items?:

              You mean the data for the model should be:
              data {song1, song2, .... } instead of data {album1 {song1, song2 ...}, album2 {song1, song2 ...}, album3 {song1, song2 ...}}

              No, data should be {{song1, album1, etc},{song2,album2,etc}}. So that each row of the model contains everything that fully describes a song.

              I want to show all songs, but they should be grouped and all groups should be visible at the same time.

              QAbstractProxyModel also has ordering capabilities, so you should be able to sort them on any role of your model, in this case you want to use the album role.

              But I don't want to filter the results.

              I was talking about filtering because a way to show the information as the screenshot you sent is to have some sort of item for each album, so you would filter on album and show only the songs from that specific album in each item, but having a single item and sorting it out also works.

              Lic-Ing. Rodrigo Lopez Gonzalez
              Embedded Software Engineer
              RidgeRun Engineering Ltd.
              www.ridgerun.com
              Email: rodrigo.lopez@ridgerun.com

              fbg13F 1 Reply Last reply
              0
              • rrlopezR rrlopez

                @fbg13 said in How to group items?:

                You mean the data for the model should be:
                data {song1, song2, .... } instead of data {album1 {song1, song2 ...}, album2 {song1, song2 ...}, album3 {song1, song2 ...}}

                No, data should be {{song1, album1, etc},{song2,album2,etc}}. So that each row of the model contains everything that fully describes a song.

                I want to show all songs, but they should be grouped and all groups should be visible at the same time.

                QAbstractProxyModel also has ordering capabilities, so you should be able to sort them on any role of your model, in this case you want to use the album role.

                But I don't want to filter the results.

                I was talking about filtering because a way to show the information as the screenshot you sent is to have some sort of item for each album, so you would filter on album and show only the songs from that specific album in each item, but having a single item and sorting it out also works.

                fbg13F Offline
                fbg13F Offline
                fbg13
                wrote on last edited by
                #7

                @rrlopez said in How to group items?:

                I was talking about filtering because a way to show the information as the screenshot you sent is to have some sort of item for each album, so you would filter on album and show only the songs from that specific album in each item, but having a single item and sorting it out also works.

                How would that look in qml though?
                Do I give my item's (TableView, Repeater etc) model the filtered-by-album model, and in the delegate I get the songs for the respective album?

                rrlopezR 1 Reply Last reply
                0
                • fbg13F fbg13

                  @rrlopez said in How to group items?:

                  I was talking about filtering because a way to show the information as the screenshot you sent is to have some sort of item for each album, so you would filter on album and show only the songs from that specific album in each item, but having a single item and sorting it out also works.

                  How would that look in qml though?
                  Do I give my item's (TableView, Repeater etc) model the filtered-by-album model, and in the delegate I get the songs for the respective album?

                  rrlopezR Offline
                  rrlopezR Offline
                  rrlopez
                  wrote on last edited by
                  #8

                  @fbg13 said in How to group items?:

                  Do I give my item's (TableView, Repeater etc) model the filtered-by-album model, and in the delegate I get the songs for the respective album?

                  Yes, your delegate will just get all songs the model has since results will be filtered on the model, so QML will not view the filtered out items.

                  Lic-Ing. Rodrigo Lopez Gonzalez
                  Embedded Software Engineer
                  RidgeRun Engineering Ltd.
                  www.ridgerun.com
                  Email: rodrigo.lopez@ridgerun.com

                  fbg13F 1 Reply Last reply
                  0
                  • rrlopezR rrlopez

                    @fbg13 said in How to group items?:

                    Do I give my item's (TableView, Repeater etc) model the filtered-by-album model, and in the delegate I get the songs for the respective album?

                    Yes, your delegate will just get all songs the model has since results will be filtered on the model, so QML will not view the filtered out items.

                    fbg13F Offline
                    fbg13F Offline
                    fbg13
                    wrote on last edited by
                    #9

                    @rrlopez said in How to group items?:

                    Yes, your delegate will just get all songs the model has since results will be filtered on the model, so QML will not view the filtered out items.

                    But if I give the filtered model to a TableView I will get only songs from 1 album in the TableView.
                    How do I get the other songs?

                    Or should this TableView be a delegate for another item?

                        Repeater {
                            // model with each album
                            model: albumsModel
                            delegate: TableView {
                                // model with songs of the current album in the repeater
                                model: songsModel
                                delegate: Song {}
                            }
                        }
                    
                    1 Reply Last reply
                    0
                    • rrlopezR Offline
                      rrlopezR Offline
                      rrlopez
                      wrote on last edited by
                      #10

                      @fbg13 said in How to group items?:

                      Or should this TableView be a delegate for another item?

                      Yeah, that's what I meant.

                      Lic-Ing. Rodrigo Lopez Gonzalez
                      Embedded Software Engineer
                      RidgeRun Engineering Ltd.
                      www.ridgerun.com
                      Email: rodrigo.lopez@ridgerun.com

                      fbg13F 1 Reply Last reply
                      0
                      • rrlopezR rrlopez

                        @fbg13 said in How to group items?:

                        Or should this TableView be a delegate for another item?

                        Yeah, that's what I meant.

                        fbg13F Offline
                        fbg13F Offline
                        fbg13
                        wrote on last edited by fbg13
                        #11

                        @rrlopez I tried what you suggested, or what I understood at least, but it's not working.

                        At the core what I have done is:

                        Repeater {
                            id: group
                            model: ["album1", "album2"]
                            delegate: Repeater {
                                model: songsProxyModel
                                Component.onCompleted: songsProxyModel.setFilterFixedString(modelData)
                                delegate: Label {
                                    text: model.artist + " - " + model.title
                                }
                            }
                        }
                        

                        But all groups have the same songs, from the last filtering.
                        Updated the repo too.

                        1 Reply Last reply
                        0
                        • rrlopezR Offline
                          rrlopezR Offline
                          rrlopez
                          wrote on last edited by
                          #12

                          Hi, your model should be something like:
                          {{song1, album1, etc},{song2,album2,etc}}
                          So each entry is a song which has an album related.

                          Lic-Ing. Rodrigo Lopez Gonzalez
                          Embedded Software Engineer
                          RidgeRun Engineering Ltd.
                          www.ridgerun.com
                          Email: rodrigo.lopez@ridgerun.com

                          fbg13F 1 Reply Last reply
                          0
                          • rrlopezR rrlopez

                            Hi, your model should be something like:
                            {{song1, album1, etc},{song2,album2,etc}}
                            So each entry is a song which has an album related.

                            fbg13F Offline
                            fbg13F Offline
                            fbg13
                            wrote on last edited by
                            #13

                            @rrlopez said in How to group items?:

                            Hi, your model should be something like:
                            {{song1, album1, etc},{song2,album2,etc}}
                            So each entry is a song which has an album related.

                            If I understand you correctly I should have a single model songsModel = {{song1, album1, etc},{song2,album2,etc}} ,
                            whose model is songsModel filtered to only hold the albums.

                            The delegate of that repeater should be another repeater (or another item with a model),
                            whose model is songsModel filtered to hold the songs of the album in the first repeater.
                            Is that correct?

                            1 Reply Last reply
                            0
                            • rrlopezR Offline
                              rrlopezR Offline
                              rrlopez
                              wrote on last edited by
                              #14

                              If I understand you correctly I should have a single model songsModel = {{song1, album1, etc},{song2,album2,etc}}
                              whose model is songsModel filtered to only hold the albums.

                              With this implementation you will have to sort each item, instead of filtering them out.
                              ListView has something named sections that will allow you to create a section for each album.

                              Lic-Ing. Rodrigo Lopez Gonzalez
                              Embedded Software Engineer
                              RidgeRun Engineering Ltd.
                              www.ridgerun.com
                              Email: rodrigo.lopez@ridgerun.com

                              fbg13F 1 Reply Last reply
                              0
                              • rrlopezR rrlopez

                                If I understand you correctly I should have a single model songsModel = {{song1, album1, etc},{song2,album2,etc}}
                                whose model is songsModel filtered to only hold the albums.

                                With this implementation you will have to sort each item, instead of filtering them out.
                                ListView has something named sections that will allow you to create a section for each album.

                                fbg13F Offline
                                fbg13F Offline
                                fbg13
                                wrote on last edited by
                                #15

                                @rrlopez said in How to group items?:

                                With this implementation you will have to sort each item, instead of filtering them out.

                                Then I really don't understand what you're suggesting with the filtering.
                                Can you provide a simple example of what you mean?

                                ListView has something named sections that will allow you to create a section for each album.

                                That's kinda what I want, but it doesn't look like I can get the songs on the right of the section, the height of the section would be ~300px.

                                1 Reply Last reply
                                0
                                • rrlopezR Offline
                                  rrlopezR Offline
                                  rrlopez
                                  wrote on last edited by
                                  #16

                                  @fbg13, this is what I meant:

                                  ColumnLayout {
                                          anchors.fill: parent
                                          RowLayout {
                                              id: group
                                              Layout.alignment: Qt.AlignTop
                                              Layout.fillHeight: true
                                              Layout.fillWidth: true
                                              ColumnLayout {
                                                  id: songs
                                                  Layout.alignment: Qt.AlignTop
                                                  Layout.fillWidth: true
                                                  Label {}
                                                  ListView {
                                                      height: contentHeight
                                                      section.property: "album"
                                                      section.delegate: Text {
                                                          text: section
                                                          font.bold: true
                                                      }
                                                      model: songsModel
                                                      delegate: SongRow {
                                                          artist: model.artist
                                                          title: model.title
                                                          album: model.album
                                                      }
                                                  }
                                              }
                                          }
                                      }
                                  

                                  I used a text as a delegate, but you can use whatever delegate you want. Let me know if it works for you.

                                  Lic-Ing. Rodrigo Lopez Gonzalez
                                  Embedded Software Engineer
                                  RidgeRun Engineering Ltd.
                                  www.ridgerun.com
                                  Email: rodrigo.lopez@ridgerun.com

                                  fbg13F 1 Reply Last reply
                                  0
                                  • rrlopezR rrlopez

                                    @fbg13, this is what I meant:

                                    ColumnLayout {
                                            anchors.fill: parent
                                            RowLayout {
                                                id: group
                                                Layout.alignment: Qt.AlignTop
                                                Layout.fillHeight: true
                                                Layout.fillWidth: true
                                                ColumnLayout {
                                                    id: songs
                                                    Layout.alignment: Qt.AlignTop
                                                    Layout.fillWidth: true
                                                    Label {}
                                                    ListView {
                                                        height: contentHeight
                                                        section.property: "album"
                                                        section.delegate: Text {
                                                            text: section
                                                            font.bold: true
                                                        }
                                                        model: songsModel
                                                        delegate: SongRow {
                                                            artist: model.artist
                                                            title: model.title
                                                            album: model.album
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    

                                    I used a text as a delegate, but you can use whatever delegate you want. Let me know if it works for you.

                                    fbg13F Offline
                                    fbg13F Offline
                                    fbg13
                                    wrote on last edited by
                                    #17

                                    @rrlopez I understood the ListView sections, but I don't think it fits my needs, since the section should hold the album cover and songs should be on the right of this image (like in the screenshot). If I add the image in the section I get this
                                    99185144-5191-459c-bb4d-799d6a89dfb3-image.png

                                    Gray area is the section, red is the "cover image".


                                    What I don't understand is your QSortFilterProxyModel and QAbstractProxyModel suggestions.

                                    @rrlopez said in How to group items?:

                                    @fbg13 I would use a QAbstractProxyModel to act as a model of your table view and change the way you define stuff in your QML.
                                    Basically add a row on the model for each song you want to display (artist, songname, artist, etc) and then access these roles on QML as model.artist, model.songname, etc.
                                    As you'll be using a QAbstractProxyModel you will have access to its sorting and filtering methods, so you will be able to filter out songs on artist. You basically will have N items where N is the number of artists, and each item from N will have a different filter to show only songs related to the corresponding artist.

                                    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