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. QStandardItemModel* gained from non-GUI thread isn`t emit itemChanged() signal

QStandardItemModel* gained from non-GUI thread isn`t emit itemChanged() signal

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 4 Posters 2.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.
  • meteoirM Offline
    meteoirM Offline
    meteoir
    wrote on last edited by
    #1

    I have started database loading in non-GUI thread with QtCuncurrent::run. In this nonGui thread I have to create QStandardItemModel* :

    QStandardItemModel* model = new QStandardItemModel;
    QStandardItem* parentItem = model->invisibleRootItem();
    

    and after that I received model in GUI thread with

    model = modelWatcher.result();
    

    on QFutureWatcher finished() signal. It works pretty (UI is builded successfully), but itemChanged() signal is not emitted on item data changes (checkbox state changed). When I creates the model in GUI thread, there are no collisions. Connect works without assert fails:

    bool ok = connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onFolderStateChanged(QStandardItem*)), static_cast<Qt::ConnectionType>(Qt::UniqueConnection));
    Q_ASSERT(ok);
    

    I know that I can't create the model (part of Qt5Gui) in nonGui thread. But what should I do and which way is correct? Also I have to declare sended type with:

    qRegisterMetaType<QStandardItemModel*>("QStandardItemModel*");
    

    Other sends like:

    qRegisterMetaType<QList<QTreeWidgetItem*> >("QList<QTreeWidgetItem*>");
    

    works good (though its also Qt5Gui part).

    How can I get the model from nonGui thread with valid pointer/meta and working itemChagned signals ?

    1 Reply Last reply
    0
    • jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      You should not use GUI related classes in non GUI threads!
      Why do you want to create QStandardItemModel in that second thread?
      That thread should not care about UI, it should read the data from the database and pass it to the UI via signals.
      UI then knows what to do with the data and how to present it to the user.
      Is there really a need for a thread to access the database?

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

      meteoirM 1 Reply Last reply
      0
      • jsulmJ jsulm

        You should not use GUI related classes in non GUI threads!
        Why do you want to create QStandardItemModel in that second thread?
        That thread should not care about UI, it should read the data from the database and pass it to the UI via signals.
        UI then knows what to do with the data and how to present it to the user.
        Is there really a need for a thread to access the database?

        meteoirM Offline
        meteoirM Offline
        meteoir
        wrote on last edited by
        #3

        @jsulm In worker thread I have read database structure and at that moment creates the QStandardItem*s with its structure. (I have read DB with external dll with code:)

        while(hasItem)
            readItem(level1) // dll function
                while(hasItem)
                    readItem(level2)
                          while(hasItem)
                                  readItem(level3)
        

        In that case I dont know the structure If I dont creates QStandardItems and model in that place. Or I need to resend all readItem`s data to GUI thread and do while loops in GUI? But it is also not a true way, as I think). Is the model can not be created in worker thread? Its a pattern MVC - model thread, view thread, correct me if I m wrong ... The best way - it creates my own class with useful values from readItem() function and send to GUI, for example, QList<MyItemClass> level1itemsList etc (level 2, level3) and do while on QLists in GUI?

        1 Reply Last reply
        0
        • jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          MVC does not say anything about multithreading. It only separates the data layer (model) from its representation (view) and the logic (controller).
          I'm wondering why you do not know the structure of the data you read from the database?
          Yes, you should pass the data from your database thread to the GUI thread, for example as QList.
          Are you sure you need an extra thread?
          Did you already encounter any issues with only one thread?

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

          meteoirM 1 Reply Last reply
          0
          • jsulmJ jsulm

            MVC does not say anything about multithreading. It only separates the data layer (model) from its representation (view) and the logic (controller).
            I'm wondering why you do not know the structure of the data you read from the database?
            Yes, you should pass the data from your database thread to the GUI thread, for example as QList.
            Are you sure you need an extra thread?
            Did you already encounter any issues with only one thread?

            meteoirM Offline
            meteoirM Offline
            meteoir
            wrote on last edited by
            #5

            @jsulm Yes, with only one thread UI is freezing(database may be >1 Gb). Structure of db is a simple recursive hierarchy, displayed as a tree with QTreeView. I will try to send only data from worker thread and build the model in GUI-thread.

            1 Reply Last reply
            0
            • dheerendraD Offline
              dheerendraD Offline
              dheerendra
              Qt Champions 2022
              wrote on last edited by
              #6

              You can create the model in worker thread. If you create the model in worker thread, you need to have event loop in thread to make the signal/slot works. Just look at the following snippet

              void MyThread::run()
              {
              qDebug() << Q_FUNC_INFO << " Creating thread"<<endl;
              model = new QStandardItemModel;
              model->setRowCount(5);
              model->setColumnCount(5);
              for (int row = 0; row < 5; ++row) {
              for (int column = 0; column < 5; ++column) {
              QStandardItem item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
              model->setItem(row, column, item);
              }
              }
              bool ok = connect(model, SIGNAL(itemChanged(QStandardItem
              )), this, SLOT(onFolderStateChanged(QStandardItem*)), static_castQt::ConnectionType(Qt::UniqueConnection));
              Q_ASSERT(ok);
              QTimer *tim = new QTimer;
              tim->setInterval(2000);
              tim->start();
              connect(tim,&QTimer::timeout,this,&MyThread::updateModel);
              qRegisterMetaType<QVector<int> >();
              exec();
              }

              QStandardItemModel *MyThread::getModel()
              {
              return model;
              }

              void MyThread::updateModel()
              {
              qDebug() << "UPdating the model"<<endl;
              QStandardItem *item = new QStandardItem("Gururaja");
              model->setItem(3,3,item);
              }

              void MyThread::onFolderStateChanged(QStandardItem *)
              {
              qDebug() << "Item is changed" << endl;
              }

              Dheerendra
              @Community Service
              Certified Qt Specialist
              http://www.pthinks.com

              meteoirM 1 Reply Last reply
              5
              • dheerendraD dheerendra

                You can create the model in worker thread. If you create the model in worker thread, you need to have event loop in thread to make the signal/slot works. Just look at the following snippet

                void MyThread::run()
                {
                qDebug() << Q_FUNC_INFO << " Creating thread"<<endl;
                model = new QStandardItemModel;
                model->setRowCount(5);
                model->setColumnCount(5);
                for (int row = 0; row < 5; ++row) {
                for (int column = 0; column < 5; ++column) {
                QStandardItem item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
                model->setItem(row, column, item);
                }
                }
                bool ok = connect(model, SIGNAL(itemChanged(QStandardItem
                )), this, SLOT(onFolderStateChanged(QStandardItem*)), static_castQt::ConnectionType(Qt::UniqueConnection));
                Q_ASSERT(ok);
                QTimer *tim = new QTimer;
                tim->setInterval(2000);
                tim->start();
                connect(tim,&QTimer::timeout,this,&MyThread::updateModel);
                qRegisterMetaType<QVector<int> >();
                exec();
                }

                QStandardItemModel *MyThread::getModel()
                {
                return model;
                }

                void MyThread::updateModel()
                {
                qDebug() << "UPdating the model"<<endl;
                QStandardItem *item = new QStandardItem("Gururaja");
                model->setItem(3,3,item);
                }

                void MyThread::onFolderStateChanged(QStandardItem *)
                {
                qDebug() << "Item is changed" << endl;
                }

                meteoirM Offline
                meteoirM Offline
                meteoir
                wrote on last edited by
                #7

                @dheerendra Sorry, but I don`t understand what do you mean as "event loop"? You mean timer that updates the model? And the reason for itemChanged signal does not work - is that the model don't know about changes and I need to update the model manually?
                In that case how can I update model with checkbox state changed data, if itemChanged() signal didn't works. (or I need use state snapshots with all items and check its difference)?

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Hi,

                  Here you can find a nice piece of documentation about QThread/QObject/Event loops.

                  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
                  1

                  • Login

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