Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved Update QHeaderView section count to reflect changes in the model

    General and Desktop
    qtreeview qheaderview
    3
    14
    5761
    Loading More Posts
    • 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.
    • S
      skebanga last edited by skebanga

      I have a QTreeView populated by a QAbstractItemModel

      I use QHeaderView::saveState/QHeaderView::restoreState on my tree view's header in order to save and restore column locations, sizes etc.

      Occasionally it is possible for additional columns to be added to the model outside of the operation of the application.

      When restoring the QHeaderView's state, the number of sections is not the same as the model's columnCount.

      There are no hidden sections.

      _model.columnCount()                 // == 20
      _tree.header()->count()              // == 15
      _tree.header()->hiddenSectionCount() // == 0
      

      I attempted to signal the QHeaderView from my model after restoring the QHeaderView's state, but this did not work

      void Model::signalAddedRows(int old_row_count)
      {
          beginInsertColumns(QModelIndex(), old_row_count, columnCount());
          endInsertColumns();
      }
      

      How can I programatically sync the QHeaderView's section count to match the model's columnCount()?

      1 Reply Last reply Reply Quote 0
      • kshegunov
        kshegunov Moderators last edited by

        Hello,
        Have you tried QHeaderView::headerDataChanged?

        Kind regards.

        Read and abide by the Qt Code of Conduct

        S 1 Reply Last reply Reply Quote 0
        • S
          skebanga @kshegunov last edited by

          Thanks for the suggestion, but it doesn't look to have an effect

          I did the following:

          std::cout << "model_columns=" <<  _model.columnCount() << " tree_columns=" << _tree.header()->count() << "\n";
          
          if (_model.columnCount() != _tree.header()->count())
          {
              for (int i = 0; i < _model.columnCount(); ++i)
              {
                  if (_tree.columnWidth(i) == 0)
                      _tree.setColumnWidth(i, 10);
              }
              _tree.header()->headerDataChanged(Qt::Horizontal, 0, _model.columnCount()); // <-- your suggestion
          }
          
          std::cout << "model_columns=" <<  _model.columnCount() << " tree_columns=" << _tree.header()->count() << "\n";
          

          The columns remain hidden, and the output is as follows:

          model_columns=31 tree_columns=28
          model_columns=31 tree_columns=28
          
          kshegunov 1 Reply Last reply Reply Quote 0
          • kshegunov
            kshegunov Moderators @skebanga last edited by

            @skebanga
            Ok, I admit it was not a very clever suggestion. Maybe better is to try to signal the view (from the model) that header data should be updated, not emitting the view's signals directly. Have you tried the model's QAbstractItemModel::headerDataChanged signal? For example:

            void Model::signalAddedRows(Qt::Orientation orientation)
            {
                emit headerDataChanged(orientation, 0, columnCount());
            }
            

            Read and abide by the Qt Code of Conduct

            S 1 Reply Last reply Reply Quote 1
            • S
              skebanga @kshegunov last edited by

              That's it! Thank you!

              All that is required is to emit the headerDataChanged signal from the model

              if (_model.columnCount() != _tree.header()->count())
                  emit _model.headerDataChanged(Qt::Horizontal, 0, _model.columnCount());
              

              The newly added columns appear now.

              Additional feedback of the change propagating is evidenced by connecting to the QHeaderView::sectionCountChanged slot:

              if (_model.columnCount() != _tree.header()->count())
              {
                  // just to prove this is working
                  connect(_tree.header(), &QHeaderView::sectionCountChanged, [](int old_count, int new_count)
                          {
                              std::cout << "sectionCountChanged: " << old_count << " -> " << new_count << "\n";
                          });
                  emit _model.headerDataChanged(Qt::Horizontal, 0, _model.columnCount());
              }
              

              Results in the following on stdout:

              sectionCountChanged: 28 -> 31
              
              kshegunov 1 Reply Last reply Reply Quote 1
              • kshegunov
                kshegunov Moderators @skebanga last edited by

                @skebanga
                You're welcome, I'm glad it worked.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply Reply Quote 0
                • SGaist
                  SGaist Lifetime Qt Champion last edited by

                  Hi,

                  Out of curiosity, are you emitting the signal from outside of the model ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  S 1 Reply Last reply Reply Quote 0
                  • S
                    skebanga @SGaist last edited by

                    @SGaist:

                    Out of curiosity, are you emitting the signal from outside of the model ?

                    I am, as detailed in my previous reply:

                    emit _model.headerDataChanged(Qt::Horizontal, 0, _model.columnCount());
                    

                    AFAIK emit is just syntactic sugar, and doesn't actually do anything.

                    So the same effect could be had by just doing:

                    _model.headerDataChanged(Qt::Horizontal, 0, _model.columnCount());
                    

                    I leave emit in just to show that it's a signal I'm calling rather than a vanilla member function

                    PS: Forgive the delay in responding, I don't have the required reputation on here to post more than 1 message every 500 seconds

                    kshegunov 1 Reply Last reply Reply Quote 1
                    • kshegunov
                      kshegunov Moderators @skebanga last edited by

                      @skebanga said:

                      Forgive the delay in responding, I don't have the required reputation on here to post more than 1 message every 500 seconds

                      Now you do. Cheers.

                      Read and abide by the Qt Code of Conduct

                      S 1 Reply Last reply Reply Quote 1
                      • S
                        skebanga @kshegunov last edited by

                        @kshegunov

                        :) thanks!

                        1 Reply Last reply Reply Quote 0
                        • SGaist
                          SGaist Lifetime Qt Champion last edited by

                          Indeed emit is a macro that turns empty. The point is that from a coding point of view, you don't "emit from another class". Signals are emitted from within the class or the sub-class you just wrote.

                          Doing like you do right now makes the code confusing and also breaks the single responsibility principle i.e. why would your containing widget play with "internals" of your model ?

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          S 2 Replies Last reply Reply Quote 0
                          • S
                            skebanga @SGaist last edited by

                            @SGaist Fair enough - point noted, thanks for the suggestion

                            1 Reply Last reply Reply Quote 0
                            • S
                              skebanga @SGaist last edited by

                              @SGaist

                              one thing to note though, re emitting a signal from externally to the model, is that this is an interplay between the view and the model.

                              The model shouldn't need to know anything about the view, but in this case, it's the fact that the model's columnCount() has increased, whilst the view's hasn't.

                              In terms of best practice, would you suggest anything in this case?

                              1 Reply Last reply Reply Quote 0
                              • SGaist
                                SGaist Lifetime Qt Champion last edited by

                                Technically the "last number of columns" is rather a model specific data. Since that part can change, the model should check the last value and then emit the signal accordingly.

                                The section ordering part, on the other hand, is indeed view specific data and the model shouldn't do anything with them.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post