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. QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program
Qt 6.11 is out! See what's new in the release blog

QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 3 Posters 453 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.
  • S Offline
    S Offline
    sairun
    wrote last edited by
    #1

    I'm developing an application to query an external web server given some user preferences. The retrieved data is stored in a local SQLite3 database. I've managed to code a functional prototype based on the Qt model/view framework, using a QTableView instance to which a model TableModel (derived from QSqlTableModel) is associated. The database to be used is passed to the model during its construction (it can be empty or partially populated with previous queries):

        _TableView = new QTableView( this );
        _TableModel = new TableModel( this, database );
        _TableModel->select();
        _TableView->setModel( _TableModel );
    

    However, during the program execution it should allow the user to change to a different database as many times as he/she likes. For that, the current database should be closed and a new one created or opened. From the documentation it's not clear what to do with the current model and the view. Before closing the database, should the model be destroyed (deleted) and a new one created? Should the model be reset (with clear()) and then associated to the new database? What about the view?

    While reading QAbstractItemView documentation I found the following comments for setModel():

    This function will create and set a new selection model, replacing any model
    that was previously set with setSelectionModel(). However, the old selection
    model will not be deleted as it may be shared between several views. We
    recommend that you delete the old selection model if it is no longer required.
    This is done with the following code:

       QItemSelectionModel *m = view->selectionModel();
       view->setModel(new model);
       delete m;
    

    The above code is not clear because it does not refer the model! The pointer *m is pointing to a QItemSelectionModel which is not the same thing. With this example I assume that one should not destroy the view when changing models, but the underlying current model should be disposed either using delete or model->deleteLater() . I'm not sure if setModel() passes the owneship of the model to the view. Apparently it does not. But one can create a model passing the view as its parent.

    I found an interesting example in github which partially answers my questions but also raises new ones. It reuses the view and destroys the model each time the users selects/creates a different database. The new models are always created with the view as their parent. It also has an odd (for me) method of destroying the model: it creates a unique_ptr pointing to the current model, which then goes out of scope when that method returns! It also nullifies the view's model, since there is no method in the view to do so.

    void MainWindow::removeCurrentModel()
    {
        std::unique_ptr<QAbstractItemModel> currentModel{ui_->tableView->model()};
        ui_->tableView->setModel(nullptr);
    }
    

    But what about SelectionModel associated with the view (as implied in the documentation of QAbstractItemView)? Does it get destroyed automatically? The documentation says

    It is up to the application to delete the old selection model if it is no
    longer needed; i.e., if it is not being used by other views. This will happen
    automatically when its parent object is deleted. However, if it does not have
    a parent, or if the parent is a long-lived object, it may be preferable to
    call its deleteLater() function to explicitly delete it.

    So, to summarize, wouldn't it be better to do

       QItemSelectionModel *oldselmod = view->selectionModel();
       QSqlTableModel *oldmodel = view->model();
       
       view->setModel(new model);
       
       oldselmod->deleteLater();
       oldmodel->deleteLater();
    
    JonBJ 1 Reply Last reply
    0
    • S sairun

      I'm developing an application to query an external web server given some user preferences. The retrieved data is stored in a local SQLite3 database. I've managed to code a functional prototype based on the Qt model/view framework, using a QTableView instance to which a model TableModel (derived from QSqlTableModel) is associated. The database to be used is passed to the model during its construction (it can be empty or partially populated with previous queries):

          _TableView = new QTableView( this );
          _TableModel = new TableModel( this, database );
          _TableModel->select();
          _TableView->setModel( _TableModel );
      

      However, during the program execution it should allow the user to change to a different database as many times as he/she likes. For that, the current database should be closed and a new one created or opened. From the documentation it's not clear what to do with the current model and the view. Before closing the database, should the model be destroyed (deleted) and a new one created? Should the model be reset (with clear()) and then associated to the new database? What about the view?

      While reading QAbstractItemView documentation I found the following comments for setModel():

      This function will create and set a new selection model, replacing any model
      that was previously set with setSelectionModel(). However, the old selection
      model will not be deleted as it may be shared between several views. We
      recommend that you delete the old selection model if it is no longer required.
      This is done with the following code:

         QItemSelectionModel *m = view->selectionModel();
         view->setModel(new model);
         delete m;
      

      The above code is not clear because it does not refer the model! The pointer *m is pointing to a QItemSelectionModel which is not the same thing. With this example I assume that one should not destroy the view when changing models, but the underlying current model should be disposed either using delete or model->deleteLater() . I'm not sure if setModel() passes the owneship of the model to the view. Apparently it does not. But one can create a model passing the view as its parent.

      I found an interesting example in github which partially answers my questions but also raises new ones. It reuses the view and destroys the model each time the users selects/creates a different database. The new models are always created with the view as their parent. It also has an odd (for me) method of destroying the model: it creates a unique_ptr pointing to the current model, which then goes out of scope when that method returns! It also nullifies the view's model, since there is no method in the view to do so.

      void MainWindow::removeCurrentModel()
      {
          std::unique_ptr<QAbstractItemModel> currentModel{ui_->tableView->model()};
          ui_->tableView->setModel(nullptr);
      }
      

      But what about SelectionModel associated with the view (as implied in the documentation of QAbstractItemView)? Does it get destroyed automatically? The documentation says

      It is up to the application to delete the old selection model if it is no
      longer needed; i.e., if it is not being used by other views. This will happen
      automatically when its parent object is deleted. However, if it does not have
      a parent, or if the parent is a long-lived object, it may be preferable to
      call its deleteLater() function to explicitly delete it.

      So, to summarize, wouldn't it be better to do

         QItemSelectionModel *oldselmod = view->selectionModel();
         QSqlTableModel *oldmodel = view->model();
         
         view->setModel(new model);
         
         oldselmod->deleteLater();
         oldmodel->deleteLater();
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote last edited by JonB
      #2

      @sairun
      Your final boxed code looks fine. (You might check for nullptr since they are pointers, just in case: delete nullptr is fine but nullptr->deleteLater() is not.)

      S 1 Reply Last reply
      0
      • JonBJ JonB

        @sairun
        Your final boxed code looks fine. (You might check for nullptr since they are pointers, just in case: delete nullptr is fine but nullptr->deleteLater() is not.)

        S Offline
        S Offline
        sairun
        wrote last edited by
        #3

        Thanks @JonB for noticing the unchecked deleteLater() but at this stage of the program I can at least be sure that the olmodel pointer is pointing to something because it was being used. Still, it's better to make sure the pointer is not null! The old selection model olselmod is another thing. In fact, the code in github that I've linked previously doesn't mention the selectionModel() anywhere in the sources. But valgrind didn't show any major leak, so I'm not sure if it is being dealt aitomatically.

        JonBJ 1 Reply Last reply
        0
        • S sairun

          Thanks @JonB for noticing the unchecked deleteLater() but at this stage of the program I can at least be sure that the olmodel pointer is pointing to something because it was being used. Still, it's better to make sure the pointer is not null! The old selection model olselmod is another thing. In fact, the code in github that I've linked previously doesn't mention the selectionModel() anywhere in the sources. But valgrind didn't show any major leak, so I'm not sure if it is being dealt aitomatically.

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

          @sairun
          I wasn't sure whether selectionModel() could potentially be nullptr if, say, you never do a selection. Probably not. But better safe than sorry.

          I rely on valgrind for checking Qt/C++ memory is being disposed correctly. If it passes you should be good. You could try not doing the disposals and verify it then complains.

          S 1 Reply Last reply
          0
          • JonBJ JonB

            @sairun
            I wasn't sure whether selectionModel() could potentially be nullptr if, say, you never do a selection. Probably not. But better safe than sorry.

            I rely on valgrind for checking Qt/C++ memory is being disposed correctly. If it passes you should be good. You could try not doing the disposals and verify it then complains.

            S Offline
            S Offline
            sairun
            wrote last edited by
            #5

            Don't get me wrong @JonB. I prefer to do the checking. The issue is whether I care about selectionModel or not. I've never had the need to directly intercat with it, although I know it is being used in my program. I rely on the selection of rows in a view to export some data.

            JonBJ 1 Reply Last reply
            0
            • S sairun

              Don't get me wrong @JonB. I prefer to do the checking. The issue is whether I care about selectionModel or not. I've never had the need to directly intercat with it, although I know it is being used in my program. I rely on the selection of rows in a view to export some data.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote last edited by
              #6

              @sairun
              Yes, if you use selection then the QItemSelectionModel will come into play. You should indeed delete or deleteLater() it as you are doing, else I think it may leak. I only meant that I do not know whether view->selectionModel() is always guaranteed to be allocated and non-nullptr, if it can be nullptr then your original unprotected code would crash, so it's worth putting in the check. I think we are on the same page :)

              Christian EhrlicherC 1 Reply Last reply
              0
              • JonBJ JonB

                @sairun
                Yes, if you use selection then the QItemSelectionModel will come into play. You should indeed delete or deleteLater() it as you are doing, else I think it may leak. I only meant that I do not know whether view->selectionModel() is always guaranteed to be allocated and non-nullptr, if it can be nullptr then your original unprotected code would crash, so it's worth putting in the check. I think we are on the same page :)

                Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote last edited by
                #7

                @JonB said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                You should indeed delete or deleteLater() it as you are doing, else I think it may leak.

                No, it does not.

                https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/itemviews/qabstractitemview.cpp#n797

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                JonBJ S 2 Replies Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  @JonB said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                  You should indeed delete or deleteLater() it as you are doing, else I think it may leak.

                  No, it does not.

                  https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/itemviews/qabstractitemview.cpp#n797

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote last edited by
                  #8

                  @Christian-Ehrlicher
                  QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel)

                  Note: It is up to the application to delete the old selection model if it is no longer needed; i.e., if it is not being used by other views. This will happen automatically when its parent object is deleted. However, if it does not have a parent, or if the parent is a long-lived object, it may be preferable to call its deleteLater() function to explicitly delete it.

                  That is what the OP is trying to follow. I do not know what his parent is. At least this is what I was thinking of, and the examples OP has found on the web.

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Christian Ehrlicher

                    @JonB said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                    You should indeed delete or deleteLater() it as you are doing, else I think it may leak.

                    No, it does not.

                    https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/itemviews/qabstractitemview.cpp#n797

                    S Offline
                    S Offline
                    sairun
                    wrote last edited by
                    #9

                    @Christian-Ehrlicher, what you mean is that per source code the QItemSelectionModel is set as a child of QAbstractItemModel and will be deleted when the latter is deleted? So I only have to deal with the model and not the selection model?

                    Christian EhrlicherC 1 Reply Last reply
                    0
                    • S sairun

                      @Christian-Ehrlicher, what you mean is that per source code the QItemSelectionModel is set as a child of QAbstractItemModel and will be deleted when the latter is deleted? So I only have to deal with the model and not the selection model?

                      Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote last edited by
                      #10

                      @sairun said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                      So I only have to deal with the model and not the selection model?

                      Yes

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      S 1 Reply Last reply
                      0
                      • Christian EhrlicherC Christian Ehrlicher

                        @sairun said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                        So I only have to deal with the model and not the selection model?

                        Yes

                        S Offline
                        S Offline
                        sairun
                        wrote last edited by
                        #11

                        @Christian-Ehrlicher said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                        Yes

                        I see. So the documentation isn't correct in the code snippet I showed above... I should mention that I implemented the deletion of the QTableModel without referencing the QItemSelectionModel` as suggested, and so far everything is working as expected. I'll mark this as solved.

                        Christian EhrlicherC 1 Reply Last reply
                        0
                        • S sairun has marked this topic as solved
                        • S sairun

                          @Christian-Ehrlicher said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                          Yes

                          I see. So the documentation isn't correct in the code snippet I showed above... I should mention that I implemented the deletion of the QTableModel without referencing the QItemSelectionModel` as suggested, and so far everything is working as expected. I'll mark this as solved.

                          Christian EhrlicherC Online
                          Christian EhrlicherC Online
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote last edited by
                          #12

                          @sairun said in QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program:

                          isn't correct in the code snippet I showed above..

                          I don't see a problem here:

                          It is up to the application to delete the old selection model if it is no
                          longer needed; i.e., if it is not being used by other views. This will happen
                          automatically when its parent object is deleted.

                          The parent is QAbstractItemView so the QISM is deleted when the itemview gets deleted.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          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