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. QSqlQueryModel and TableView for dynamic data

QSqlQueryModel and TableView for dynamic data

Scheduled Pinned Locked Moved Solved QML and Qt Quick
24 Posts 4 Posters 6.4k Views
  • 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.
  • X Offline
    X Offline
    XDePedro
    wrote on last edited by
    #1

    I am pretty new in Qt/QML.

    Trying to build an application with a UI in QML and accessing data from a Sqlite database.

    The QML view has a TableView to display information in a data grid wiht a model in C++.

    The model is a class inheriting from QSqlQueryModel with a query to the database: setQuery("SELECT * FROM Samples", GetDataBase())

    I am adding a new row in the database table every second in another thread.

    When I navigate to the view where the TableView is placed the grid is populated with the information in the table. All good. But then, everytime I add a new row I call setQuery again but the table is not updated. If I go back and forth to the view again it is populated with all the new rows.

    I thought the view was "automaticaly" notified whenever the model changed but I suppose I am missing any kind of notification to let the view know that there is new rows or something??

    Also...this is just a testing application but I forsee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order handred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.

    Thanks in advance.

    KillerSmathK JonBJ 2 Replies Last reply
    0
    • X XDePedro

      I am pretty new in Qt/QML.

      Trying to build an application with a UI in QML and accessing data from a Sqlite database.

      The QML view has a TableView to display information in a data grid wiht a model in C++.

      The model is a class inheriting from QSqlQueryModel with a query to the database: setQuery("SELECT * FROM Samples", GetDataBase())

      I am adding a new row in the database table every second in another thread.

      When I navigate to the view where the TableView is placed the grid is populated with the information in the table. All good. But then, everytime I add a new row I call setQuery again but the table is not updated. If I go back and forth to the view again it is populated with all the new rows.

      I thought the view was "automaticaly" notified whenever the model changed but I suppose I am missing any kind of notification to let the view know that there is new rows or something??

      Also...this is just a testing application but I forsee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order handred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.

      Thanks in advance.

      KillerSmathK Offline
      KillerSmathK Offline
      KillerSmath
      wrote on last edited by
      #2

      @XDePedro Can you show a piece of your Model code ?

      @Computer Science Student - Brazil
      Web Developer and Researcher
      “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

      X 1 Reply Last reply
      0
      • X XDePedro

        I am pretty new in Qt/QML.

        Trying to build an application with a UI in QML and accessing data from a Sqlite database.

        The QML view has a TableView to display information in a data grid wiht a model in C++.

        The model is a class inheriting from QSqlQueryModel with a query to the database: setQuery("SELECT * FROM Samples", GetDataBase())

        I am adding a new row in the database table every second in another thread.

        When I navigate to the view where the TableView is placed the grid is populated with the information in the table. All good. But then, everytime I add a new row I call setQuery again but the table is not updated. If I go back and forth to the view again it is populated with all the new rows.

        I thought the view was "automaticaly" notified whenever the model changed but I suppose I am missing any kind of notification to let the view know that there is new rows or something??

        Also...this is just a testing application but I forsee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order handred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.

        Thanks in advance.

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

        @XDePedro said in QSqlQueryModel and TableView for dynamic data:

        Also...this is just a testing application but I forsee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order handred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.

        I hope you're not intending to display 100,000 rows to your user in the grid??

        I don't know whether you intend to display all rows including those which were previously shown, as well as your new rows? Or new rows only? To save on database query bandwidth, with the kind of numbers you are talking about you really only want to be fetching extra, new rows, not all of them each time....

        X 1 Reply Last reply
        0
        • KillerSmathK KillerSmath

          @XDePedro Can you show a piece of your Model code ?

          X Offline
          X Offline
          XDePedro
          wrote on last edited by
          #4

          @KillerSmath

          Is just a testing app:

          In the model constructor (it subclass QSqlQueryModel) I create the db and set the query:

                  QSqlDatabase *pDB = new QSqlDatabase();
                  *pDB = QSqlDatabase::addDatabase("QSQLITE");
                  pDB->setDatabaseName(":memory:");
                  if(!pDB->open())
                  {
                      assert(false);
                  }
          
                  QSqlQuery query;
                  query.prepare("CREATE TABLE samples(id PRIMARY KEY, sampleId TEXT);");
                  if(!query.exec())
                  {
                      assert(false);
                  }
                  pFakeDB = std::unique_ptr<QSqlDatabase>(pDB);
          
          

          Then start the thread to update the database and connect a slot to the database change notification:

             moveToThread(&fakeDBWorkingThread);
              connect(&fakeDBWorkingThread, SIGNAL(started()), this, SLOT(GenerateFakeData()));
              connect(this, SIGNAL(finished()), &fakeDBWorkingThread, SLOT(quit()));
              connect(this, SIGNAL(dbChanged()), this, SLOT(ChangeDBQuery()));
              fakeDBWorkingThread.start();
          

          And set the query:

            QSqlQuery query(GetDataBase());
             query.exec("SELECT * FROM Samples");
             setQuery(query);
          

          In the slot that is called when a new db item is added:

              setQuery(query());
          

          But I tried several things...as I told you, the table is populated correctly when I enter the view...is jus the update mechanism not working.

          1 Reply Last reply
          0
          • JonBJ JonB

            @XDePedro said in QSqlQueryModel and TableView for dynamic data:

            Also...this is just a testing application but I forsee that in my real app the information to be displayed in the grid will change very fast and the table can have several rows of information (order handred thousand rows) so I wonder if QSqlQueryModel is the right model for this kind data.

            I hope you're not intending to display 100,000 rows to your user in the grid??

            I don't know whether you intend to display all rows including those which were previously shown, as well as your new rows? Or new rows only? To save on database query bandwidth, with the kind of numbers you are talking about you really only want to be fetching extra, new rows, not all of them each time....

            X Offline
            X Offline
            XDePedro
            wrote on last edited by
            #5

            @JonB
            I want to display all but not at the same time....I though the table has its own pagination mechanism and is not getting all the information from the db if the user does not scroll it.

            If not then this is not the right control/model.

            JonBJ 1 Reply Last reply
            0
            • X XDePedro

              @JonB
              I want to display all but not at the same time....I though the table has its own pagination mechanism and is not getting all the information from the db if the user does not scroll it.

              If not then this is not the right control/model.

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

              @XDePedro
              Unfortunately, none of the QSql... classes do virtual pagination, which you have rightly said is what you need. This is for you to add if wanted! You can make the code simpler if it suits to only allow append and page-forward in the table view.... I think I may have seen some project somewhere which offers code for pagination, but you'll have to Google/stackoverflow....

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

                Hi,

                Just a side note, you're using QSqlDatabase wrongly. There's no need for that pointer.

                See the class documentation for how to handle it.

                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
                0
                • X Offline
                  X Offline
                  XDePedro
                  wrote on last edited by
                  #8

                  If the db has enough elements to get the scrollbar in the table, then just scrolling the table the new elements are populated....so I suppose I'm missing any kind of notification so that the TableView is updated...just can't figure out how.

                  JonBJ 1 Reply Last reply
                  0
                  • X XDePedro

                    If the db has enough elements to get the scrollbar in the table, then just scrolling the table the new elements are populated....so I suppose I'm missing any kind of notification so that the TableView is updated...just can't figure out how.

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

                    @XDePedro
                    Not sure what you mean. Scrolling a table view does not fetch new elements via a new SQL query on the database....

                    X 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @XDePedro
                      Not sure what you mean. Scrolling a table view does not fetch new elements via a new SQL query on the database....

                      X Offline
                      X Offline
                      XDePedro
                      wrote on last edited by
                      #10

                      @JonB

                      Is not the table view fetching for new elements. If I just resize it just to make it redraw...the new elements are also displayed.

                      I am calling setQuery in the model everytime the database changes so I suppose the query is ok and the data is there....but just calling setQuery doesn't make the TableView to update.

                      How can I force the table view to update from the model?

                      JonBJ 1 Reply Last reply
                      0
                      • X XDePedro

                        @JonB

                        Is not the table view fetching for new elements. If I just resize it just to make it redraw...the new elements are also displayed.

                        I am calling setQuery in the model everytime the database changes so I suppose the query is ok and the data is there....but just calling setQuery doesn't make the TableView to update.

                        How can I force the table view to update from the model?

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

                        @XDePedro
                        For the update, see posts like:

                        • http://www.qtcentre.org/threads/58700-How-to-update-QTableView-from-SQL-database-after-adding-data-to-database
                        • https://forum.qt.io/topic/1168/solved-the-best-way-to-programmatically-refresh-a-qsqlquerymodel-when-the-content-of-the-query-changes/13
                        • https://stackoverflow.com/questions/45359569/how-to-update-qtableview-on-qabstracttablemodel-change

                        However, I don't see how this addresses what I see as your issue, which is that you have "hundreds of thousands of rows" to display. You do not want to fetch all of them each time, you do not want to store them all in your model, nor in your view.... IMHO you only want to fetch some kind of "page" at a time of rows, or something along those lines.

                        1 Reply Last reply
                        0
                        • X Offline
                          X Offline
                          XDePedro
                          wrote on last edited by
                          #12

                          I know maybe this not the right model but anyway I would like to make it work before looking for another solution.

                          I notice that I'm getting this error message:

                          QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
                          (Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().)

                          can it be the root cause? Does naybody know why I'm getting this? Might it be related with the fact that is another thread who is calling the setQuery??

                          1 Reply Last reply
                          0
                          • KillerSmathK Offline
                            KillerSmathK Offline
                            KillerSmath
                            wrote on last edited by
                            #13

                            @XDePedro

                            Possible explation for your problem.

                            @Computer Science Student - Brazil
                            Web Developer and Researcher
                            “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                            1 Reply Last reply
                            0
                            • KillerSmathK Offline
                              KillerSmathK Offline
                              KillerSmath
                              wrote on last edited by
                              #14

                              Executing query in Main Thread after DB Changed

                               connect(populateWorker, &populateWorker::doneSignal, [this](){
                                 QSqlQuery query(*database);
                                 database->open();
                              
                                 query->setQuery("SELECT * FROM Samples");
                                 query->exec();
                                 
                                 model->setQuery(query);
                              
                                 database->close();
                              });
                              

                              @Computer Science Student - Brazil
                              Web Developer and Researcher
                              “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                              X 1 Reply Last reply
                              0
                              • KillerSmathK KillerSmath

                                Executing query in Main Thread after DB Changed

                                 connect(populateWorker, &populateWorker::doneSignal, [this](){
                                   QSqlQuery query(*database);
                                   database->open();
                                
                                   query->setQuery("SELECT * FROM Samples");
                                   query->exec();
                                   
                                   model->setQuery(query);
                                
                                   database->close();
                                });
                                
                                X Offline
                                X Offline
                                XDePedro
                                wrote on last edited by
                                #15

                                @KillerSmath
                                How is this different that I was doing?

                                You added the slot in a lambda but is still executed in the working thread, as far as I know, Or I am missing anything.

                                I tried and seems not to work.

                                1 Reply Last reply
                                0
                                • KillerSmathK Offline
                                  KillerSmathK Offline
                                  KillerSmath
                                  wrote on last edited by
                                  #16

                                  I am not expert with QThread but my suggest is create a class (DataManager) that will be the bridge between QML and C++ Model.

                                  • You can create a QThread inside this class to move the worker object to this thread.

                                  • Run your GenerateFakeData function from this worker and connect the doneSignal to setQuery Slot in DataManager

                                  • Allow the acess to model by this class

                                  @Computer Science Student - Brazil
                                  Web Developer and Researcher
                                  “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                                  1 Reply Last reply
                                  0
                                  • X Offline
                                    X Offline
                                    XDePedro
                                    wrote on last edited by
                                    #17

                                    Ok. Now is working. It was a problem with the worker thread. I stopped the code in the code that updated the query (setQuery) in my previous implementation and was executed in the working thread. With current implementation the setQuery is executed in the UI thread.

                                    In fact with current implementation the code is executed in one thread or the other just depending on how I made the signal/slot connection. So if I connect them this way:

                                            connect(&insertWorker, SIGNAL(dbChanged()), this, SLOT(DBUpdated()));
                                    
                                    
                                        void SampleListModel::DBUpdated()
                                        {
                                            QSqlQuery query;/
                                            query.exec("SELECT * FROM Samples");
                                            setQuery(query);
                                        }
                                    

                                    Everything works and the setQuery is executed in the UI thread.

                                    But if I do it this way:

                                            connect(    &insertWorker,
                                                        &DBWorker::dbChanged,
                                                        [this]()
                                                        {
                                                            QSqlQuery query(GetDataBase());
                                                            query.exec("SELECT * FROM Samples");
                                                            setQuery(query);
                                                        });
                                    

                                    Then the lambda code is executed in the worker thread and the real-time updates are not working.

                                    As I said I am pretty new in Qt so I wonder whats the difference and if someone can recommend a good article explainning how the thread model works in Qt.

                                    Thanks for all your help.

                                    JonBJ 1 Reply Last reply
                                    1
                                    • KillerSmathK Offline
                                      KillerSmathK Offline
                                      KillerSmath
                                      wrote on last edited by
                                      #18

                                      You welcome.
                                      I also had difficulty with threads when i was starting to coding in QT but as time goes on, you'll understand why threads are very limited because of their unpredictability.

                                      @Computer Science Student - Brazil
                                      Web Developer and Researcher
                                      “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                                      1 Reply Last reply
                                      0
                                      • X XDePedro

                                        Ok. Now is working. It was a problem with the worker thread. I stopped the code in the code that updated the query (setQuery) in my previous implementation and was executed in the working thread. With current implementation the setQuery is executed in the UI thread.

                                        In fact with current implementation the code is executed in one thread or the other just depending on how I made the signal/slot connection. So if I connect them this way:

                                                connect(&insertWorker, SIGNAL(dbChanged()), this, SLOT(DBUpdated()));
                                        
                                        
                                            void SampleListModel::DBUpdated()
                                            {
                                                QSqlQuery query;/
                                                query.exec("SELECT * FROM Samples");
                                                setQuery(query);
                                            }
                                        

                                        Everything works and the setQuery is executed in the UI thread.

                                        But if I do it this way:

                                                connect(    &insertWorker,
                                                            &DBWorker::dbChanged,
                                                            [this]()
                                                            {
                                                                QSqlQuery query(GetDataBase());
                                                                query.exec("SELECT * FROM Samples");
                                                                setQuery(query);
                                                            });
                                        

                                        Then the lambda code is executed in the worker thread and the real-time updates are not working.

                                        As I said I am pretty new in Qt so I wonder whats the difference and if someone can recommend a good article explainning how the thread model works in Qt.

                                        Thanks for all your help.

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

                                        @XDePedro
                                        I can't get my head around each of your two code approaches, but it's important to understand that all database objects/operations are constructed/performed in the same thread as each other, not in/from different threads. Is that the situation you are in now/does that explain anything not working?

                                        X 1 Reply Last reply
                                        0
                                        • JonBJ JonB

                                          @XDePedro
                                          I can't get my head around each of your two code approaches, but it's important to understand that all database objects/operations are constructed/performed in the same thread as each other, not in/from different threads. Is that the situation you are in now/does that explain anything not working?

                                          X Offline
                                          X Offline
                                          XDePedro
                                          wrote on last edited by
                                          #20

                                          @JonB
                                          Database insertions/write are done in the working thread.
                                          Database queries/reads are done in the UI thread.

                                          JonBJ 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