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. emit dataChanged refreshes QTableView only once.

emit dataChanged refreshes QTableView only once.

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 4 Posters 1.7k 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.
  • S Offline
    S Offline
    sweetMango
    wrote on last edited by
    #1

    Hi!

    I'm working on my code actually and I spotted a problem. I have an app that filters files. Every time I add new filter to QTreeView I want to refresh view and add it to Table. So far I created code like this

    //constructor
    
    FilterModel::FilterModel(QObject* parent, const std::shared_ptr<FilterManager>& filterManager)
        : QAbstractTableModel(parent), mFilterManager(filterManager)
    {
        mFilterManager->addListener([this](unsigned int id){
            QModelIndex idx1 = index(mFilterManager->getIndexById(id), NAME_COLUMN);
            QModelIndex idx2 = index(mFilterManager->getIndexById(id), DESCRIPTION_COLUMN);
            emit dataChanged(idx1, idx2, QVector<int>{Qt::DisplayRole});
        }
        );
    }
    
    //Add Listener method
    
    void FilterManager::addListener(std::function<void(unsigned int)> f)
    {
        listeners.append(f);
    }
    
    
    //notify method
    
    void FilterManager::notifyListeners(unsigned int id)
    {
        for (auto&& listener : listeners)
        {
            listener(id);
        }
    }
    

    notifyListeners is triggered every time data changes (eg. filter is added or activity is changed). View refreshes only when I resize window, and do it once in one execution of program.

    I'm using 5.2.1, on Ubuntu.

    Thanks.

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

      can you add:

      • connect(this,&FilterModel::dataChanged,[](){qDebug("changed");}); to FilterModel::FilterModel to make sure the signal is emitted
      • Q_ASSERT(idx1.isValid()); Q_ASSERT(idx2 .isValid()); to the lambda inside addListener to make sure you are passing valid indexes to the view

      "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

      S 1 Reply Last reply
      4
      • sierdzioS Offline
        sierdzioS Offline
        sierdzio
        Moderators
        wrote on last edited by
        #3

        So each time you update something, you are calling your listener functions, right?

        Are you sure you are passing valid ids to them? Are you sure the constructed idx1 and idx2 are valid and correct?

        Are you sure dataChanged() is really being emitted? Because you are trying to emit it from a different object (FilterManager instead of FilterModel)?

        (Z(:^

        1 Reply Last reply
        4
        • S sweetMango

          Hi!

          I'm working on my code actually and I spotted a problem. I have an app that filters files. Every time I add new filter to QTreeView I want to refresh view and add it to Table. So far I created code like this

          //constructor
          
          FilterModel::FilterModel(QObject* parent, const std::shared_ptr<FilterManager>& filterManager)
              : QAbstractTableModel(parent), mFilterManager(filterManager)
          {
              mFilterManager->addListener([this](unsigned int id){
                  QModelIndex idx1 = index(mFilterManager->getIndexById(id), NAME_COLUMN);
                  QModelIndex idx2 = index(mFilterManager->getIndexById(id), DESCRIPTION_COLUMN);
                  emit dataChanged(idx1, idx2, QVector<int>{Qt::DisplayRole});
              }
              );
          }
          
          //Add Listener method
          
          void FilterManager::addListener(std::function<void(unsigned int)> f)
          {
              listeners.append(f);
          }
          
          
          //notify method
          
          void FilterManager::notifyListeners(unsigned int id)
          {
              for (auto&& listener : listeners)
              {
                  listener(id);
              }
          }
          

          notifyListeners is triggered every time data changes (eg. filter is added or activity is changed). View refreshes only when I resize window, and do it once in one execution of program.

          I'm using 5.2.1, on Ubuntu.

          Thanks.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @sweetMango
          I'm not sure what you're saying you do/do not want, or what you are/are not seeing, but I think the view only refreshes when it next hits the event loop and gets time to repaint, no matter how many times it might have received & acted on multiple dataChanged signals. If you want it to update immediately on each one, I think you need to call http://doc.qt.io/qt-5/qwidget.html#repaint. But maybe that's not what you mean....

          EDIT Looks like @VRonin understands what you're saying better than I do, sorry!

          1 Reply Last reply
          2
          • VRoninV VRonin

            can you add:

            • connect(this,&FilterModel::dataChanged,[](){qDebug("changed");}); to FilterModel::FilterModel to make sure the signal is emitted
            • Q_ASSERT(idx1.isValid()); Q_ASSERT(idx2 .isValid()); to the lambda inside addListener to make sure you are passing valid indexes to the view
            S Offline
            S Offline
            sweetMango
            wrote on last edited by
            #5

            @VRonin
            I've applied your suggestions, and every time I add filter, console shows "changed", so signal is emitted, but view refreshes only once in lifetime of program.

            @sierdzio
            Yes, every time I change something, I'm calling notifyListeners. I'm pretty sure, that ids are correct. The goal is to refresh only one row in view, with specific filter. So before refresh it don't exist in View, but after refresh I want it to pop up in
            QTableView.

            @JonB
            Still thanks for your reply!

            VRoninV sierdzioS JonBJ 3 Replies Last reply
            0
            • S sweetMango

              @VRonin
              I've applied your suggestions, and every time I add filter, console shows "changed", so signal is emitted, but view refreshes only once in lifetime of program.

              @sierdzio
              Yes, every time I change something, I'm calling notifyListeners. I'm pretty sure, that ids are correct. The goal is to refresh only one row in view, with specific filter. So before refresh it don't exist in View, but after refresh I want it to pop up in
              QTableView.

              @JonB
              Still thanks for your reply!

              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6

              @sweetMango said in emit dataChanged refreshes QTableView only once.:

              So before refresh it don't exist in View, but after refresh I want it to pop up in

              Ok, this is the key of the problem.

              dataChanged only refreshes the contents of existing indexes. You need to use beginInsertRows/endInsertRows to notify the view of new rows spawning

              Edit:
              sorry for the double ninja @sierdzio

              "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
              3
              • S sweetMango

                @VRonin
                I've applied your suggestions, and every time I add filter, console shows "changed", so signal is emitted, but view refreshes only once in lifetime of program.

                @sierdzio
                Yes, every time I change something, I'm calling notifyListeners. I'm pretty sure, that ids are correct. The goal is to refresh only one row in view, with specific filter. So before refresh it don't exist in View, but after refresh I want it to pop up in
                QTableView.

                @JonB
                Still thanks for your reply!

                sierdzioS Offline
                sierdzioS Offline
                sierdzio
                Moderators
                wrote on last edited by
                #7

                @sweetMango said in emit dataChanged refreshes QTableView only once.:

                don't exist in View, but after refresh I want it to pop up in
                QTableView.

                Then dataChanged is wrong. You need to use beginInsertRows() and endInsertRows() instead.

                (Z(:^

                1 Reply Last reply
                4
                • S sweetMango

                  @VRonin
                  I've applied your suggestions, and every time I add filter, console shows "changed", so signal is emitted, but view refreshes only once in lifetime of program.

                  @sierdzio
                  Yes, every time I change something, I'm calling notifyListeners. I'm pretty sure, that ids are correct. The goal is to refresh only one row in view, with specific filter. So before refresh it don't exist in View, but after refresh I want it to pop up in
                  QTableView.

                  @JonB
                  Still thanks for your reply!

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @sweetMango
                  As @sierdzio has just beaten me to posting: when changing the model:

                  • If data in an existing row has changed, you need to emit dataChanged.
                  • But if a new row has been inserted or an existing row deleted you need to call begin/endInsert/DeleteRows().

                  The view needs to know differently from dataChanged when the number of rows changes.

                  1 Reply Last reply
                  4
                  • S Offline
                    S Offline
                    sweetMango
                    wrote on last edited by sweetMango
                    #9

                    @VRonin
                    @sierdzio
                    @JonB

                    Nice! Thanks a lot!

                    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