Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Need a suggestion for displaying song information
Forum Updated to NodeBB v4.3 + New Features

Need a suggestion for displaying song information

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 6 Posters 2.5k 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.
  • J Offline
    J Offline
    jsmolka
    wrote on last edited by
    #1

    Hey,

    I am currently working on a music player and I ran into an issue. At startup I am loading all audio files from a directory and parse their tags. That takes around 400ms which I am willing to take as delay for the moment (might move it into a seperate thread in the future). After I have loaded all those files I use a QListWidget to display them in a certain manner which looks like this:

    Screenshot

    This approach (especially painting) takes quiet some time and blocks the user interface in the process. What I would like to have is a more efficient approach, maybe one that loads items just when they are needed. I have seen this example and I might be able to implement it.

    My question: Whats the recommended and optimal way to display those information? I have already thought about QTableView but I would like to use a layout (which does not seem to be supported). It would be really nice if you could link me to some examples because I am quite new to Qt.

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      How are you laying out each row at the moment?

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      1
      • J Offline
        J Offline
        jsmolka
        wrote on last edited by
        #3

        @VRonin

        Currently I am looping over every audio file with this loop

        void MusicLibrary::loadAudios(Audios audios)
        {
            clear();
        
            for (Audio *audio : audios)
            {
                SongInfo *info = new SongInfo(audio, this);
                info->showTitle();
                info->showArtist();
                info->showAlbum();
                info->showYear();
                info->showGenre();
                info->showLength(Qt::AlignRight);
                info->init({10, 10, 10, 1, 10, 1});
        
                QListWidgetItem *item = new QListWidgetItem(this);
                item->setSizeHint(QSize(0, Config::Library::itemHeight()));
                addItem(item);
                setItemWidget(item, info);
            }
        }
        

        The show functions create a label each. The init function loops over every created label and places it in a box layout.

        void SongInfo::init(const QVector<int> &stretches)
        {
            QHBoxLayout *layout = new QHBoxLayout(this);
            for (int i = 0; i < m_labels.size(); i++)
                layout->addWidget(m_labels[i], stretches[i]);
            setLayout(layout);
        }
        
        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #4

          setItemWidget should come with a huge "nuclear hazard" label on it.

          The correct way to go is using QTableWidget to have different columns instead of QListWidget and use a subclass of QStyledItemDelegate to customise the painting if you need to.

          You can store your data in the model using QTableWidgetItem::setData, you should not store it in the item widget (as it defeats the purpose of having a model at all)

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          4
          • J Offline
            J Offline
            jsmolka
            wrote on last edited by
            #5

            @VRonin

            Thanks you! I have implemented your suggestions and the load times decreased noticeably. I had to add a QStyleItemDelegate to extend the hover style to a row level.

            Let's say I start my app and load the songs in the background. What's the best way to update the table without blocking the user interface or even just load the needed items?

            jsulmJ 1 Reply Last reply
            0
            • J jsmolka

              @VRonin

              Thanks you! I have implemented your suggestions and the load times decreased noticeably. I had to add a QStyleItemDelegate to extend the hover style to a row level.

              Let's say I start my app and load the songs in the background. What's the best way to update the table without blocking the user interface or even just load the needed items?

              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @jsmolka You could scan your songs in another thread and emit signals to GUI thread where you update the UI

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              1
              • J Offline
                J Offline
                jsmolka
                wrote on last edited by
                #7

                @jsulm I have already tried that using the QListWidget. Problem there was that 1500 songs were scanned in 500ms and I emitted a signal for each one of them. As a result of that the UI updated at once (and got blocked) instead of inserting the songs one by one. But I will try again with the QTableWidget. Thank you.

                1 Reply Last reply
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  I'm still a bit perplexed, 1500 data points is not a lot, it should work seamlessly.

                  Can we try one thing? remove the delegate and just store the song title in the first column as a string in Qt::EditRole and nothing else, see if that works faster

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  1 Reply Last reply
                  1
                  • J Offline
                    J Offline
                    jsmolka
                    wrote on last edited by
                    #9

                    @VRonin

                    I am doing the following now (without delegate)

                    void MusicLibrary::loadAudios(Audios audios)
                    {
                        clear();
                    
                        setRowCount(audios.size());
                        setColumnCount(1);
                    
                        setUpdatesEnabled(false);
                        for (int i = 0; i < audios.size(); i++)
                        {
                            QTableWidgetItem *item = new QTableWidgetItem;
                            item->setData(Qt::EditRole, audios[i]->title());
                            setItem(i, 0, item);
                        }
                        setUpdatesEnabled(true);
                    }
                    

                    It's not slow but it's not seemless either. Not sure if it helps but those are the changes I made to the QTableWidget.

                    setAlternatingRowColors(true);
                    setEditTriggers(QAbstractItemView::NoEditTriggers);
                    setFocusPolicy(Qt::NoFocus);
                    setFrameStyle(QFrame::NoFrame);
                    //setItemDelegate(new RowHoverDelegate(this, this));
                    setSelectionMode(QAbstractItemView::NoSelection);
                    setShowGrid(false);
                    setStyleSheet(loadStyleSheet());
                    setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);   
                    setWordWrap(false);
                    
                    horizontalHeader()->hide();
                    horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
                    horizontalScrollBar()->hide();
                    
                    verticalHeader()->hide();
                    
                    jsulmJ 1 Reply Last reply
                    0
                    • J jsmolka

                      @VRonin

                      I am doing the following now (without delegate)

                      void MusicLibrary::loadAudios(Audios audios)
                      {
                          clear();
                      
                          setRowCount(audios.size());
                          setColumnCount(1);
                      
                          setUpdatesEnabled(false);
                          for (int i = 0; i < audios.size(); i++)
                          {
                              QTableWidgetItem *item = new QTableWidgetItem;
                              item->setData(Qt::EditRole, audios[i]->title());
                              setItem(i, 0, item);
                          }
                          setUpdatesEnabled(true);
                      }
                      

                      It's not slow but it's not seemless either. Not sure if it helps but those are the changes I made to the QTableWidget.

                      setAlternatingRowColors(true);
                      setEditTriggers(QAbstractItemView::NoEditTriggers);
                      setFocusPolicy(Qt::NoFocus);
                      setFrameStyle(QFrame::NoFrame);
                      //setItemDelegate(new RowHoverDelegate(this, this));
                      setSelectionMode(QAbstractItemView::NoSelection);
                      setShowGrid(false);
                      setStyleSheet(loadStyleSheet());
                      setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);   
                      setWordWrap(false);
                      
                      horizontalHeader()->hide();
                      horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
                      horizontalScrollBar()->hide();
                      
                      verticalHeader()->hide();
                      
                      jsulmJ Offline
                      jsulmJ Offline
                      jsulm
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @jsmolka You could emit a signal for a set of songs, lets say for 10.

                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                      J.HilkJ 1 Reply Last reply
                      1
                      • jsulmJ jsulm

                        @jsmolka You could emit a signal for a set of songs, lets say for 10.

                        J.HilkJ Offline
                        J.HilkJ Offline
                        J.Hilk
                        Moderators
                        wrote on last edited by
                        #11

                        @jsulm said in Need a suggestion for displaying song information:

                        @jsmolka You could emit a signal for a set of songs, lets say for 10.

                        Mmh, correct me if I'm wrong here, but, as long as the loop is going on, the Repaint event is postponed until the next time the event loop ist processed 🤔

                        The op would need to do something like calling processEvents() to update the ui. QThread is not an option, as QTableWidgetItem is a gui element and therefore may only be processed in the main thread!?


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        jsulmJ 1 Reply Last reply
                        0
                        • J.HilkJ J.Hilk

                          @jsulm said in Need a suggestion for displaying song information:

                          @jsmolka You could emit a signal for a set of songs, lets say for 10.

                          Mmh, correct me if I'm wrong here, but, as long as the loop is going on, the Repaint event is postponed until the next time the event loop ist processed 🤔

                          The op would need to do something like calling processEvents() to update the ui. QThread is not an option, as QTableWidgetItem is a gui element and therefore may only be processed in the main thread!?

                          jsulmJ Offline
                          jsulmJ Offline
                          jsulm
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          @J.Hilk I suggested to use an extra thread for music file scanning. From this thread he is emitting a signal with music data which is then handled in the GUI thread. His problem is now that he is emitting the signal for each song and thus flooding the GUI thread. That's why I suggested to group the song data to not to emit too many signals. I did NOT suggest to use GUI related classes in other threads than GUI thread. If he is using such classes in this second thread then it is clearly wrong (I did not check his code that thoroughly).

                          https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          2
                          • M Offline
                            M Offline
                            Mr Gisa
                            wrote on last edited by Mr Gisa
                            #13

                            Perhaps you could use Qt Concurrent, specially if you want to add a sugar progress to the process. https://doc.qt.io/qt-5.10/qtconcurrent-index.html

                            I don't think you need to create a worker thread class just to make this simple thing as you already have the Qt Concurrent to do that for you in a simply way. You can even, pause/continue and stop the process with it.

                            1 Reply Last reply
                            0
                            • J Offline
                              J Offline
                              jsmolka
                              wrote on last edited by jsmolka
                              #14

                              Thanks for all your suggestion. With a seperate thread for loading and the QTableWidget instead of QListWidget all runs smoothly.

                              Just another question out of curiosity. If I create a QTableWidgetItem on the heap, do I have to delete it manually? Because there is no parent property unlike in most of Qt's classes.

                              JonBJ 1 Reply Last reply
                              0
                              • M Offline
                                M Offline
                                Mr Gisa
                                wrote on last edited by
                                #15

                                @jsmolka I don't think that you need to delete it manually as the widget will take the ownership of the item.

                                1 Reply Last reply
                                1
                                • J jsmolka

                                  Thanks for all your suggestion. With a seperate thread for loading and the QTableWidget instead of QListWidget all runs smoothly.

                                  Just another question out of curiosity. If I create a QTableWidgetItem on the heap, do I have to delete it manually? Because there is no parent property unlike in most of Qt's classes.

                                  JonBJ Online
                                  JonBJ Online
                                  JonB
                                  wrote on last edited by JonB
                                  #16

                                  @jsmolka

                                  @Mr-Gisa is correct.

                                  http://doc.qt.io/qt-5/qtablewidget.html#setItem

                                  The table takes ownership of the item

                                  See also https://stackoverflow.com/a/21998917/489865

                                  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