QSqlTableModel, QTableView and sqlite databases: how to use/reuse them in the same program
-
I'm developing an application to query an external web server given some user preferences. The retrieved data is stored in a local
SQLite3database. I've managed to code a functional prototype based on the Qt model/view framework, using aQTableViewinstance to which a modelTableModel(derived fromQSqlTableModel) 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
QAbstractItemViewdocumentation I found the following comments forsetModel():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
*mis pointing to aQItemSelectionModelwhich 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 usingdeleteormodel->deleteLater(). I'm not sure ifsetModel()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_ptrpointing 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
SelectionModelassociated with the view (as implied in the documentation ofQAbstractItemView)? Does it get destroyed automatically? The documentation saysIt 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(); -
I'm developing an application to query an external web server given some user preferences. The retrieved data is stored in a local
SQLite3database. I've managed to code a functional prototype based on the Qt model/view framework, using aQTableViewinstance to which a modelTableModel(derived fromQSqlTableModel) 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
QAbstractItemViewdocumentation I found the following comments forsetModel():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
*mis pointing to aQItemSelectionModelwhich 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 usingdeleteormodel->deleteLater(). I'm not sure ifsetModel()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_ptrpointing 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
SelectionModelassociated with the view (as implied in the documentation ofQAbstractItemView)? Does it get destroyed automatically? The documentation saysIt 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(); -
@sairun
Your final boxed code looks fine. (You might check fornullptrsince they are pointers, just in case:delete nullptris fine butnullptr->deleteLater()is not.)Thanks @JonB for noticing the unchecked
deleteLater()but at this stage of the program I can at least be sure that theolmodelpointer is pointing to something because it was being used. Still, it's better to make sure the pointer is not null! The old selection modelolselmodis another thing. In fact, the code in github that I've linked previously doesn't mention theselectionModel()anywhere in the sources. But valgrind didn't show any major leak, so I'm not sure if it is being dealt aitomatically. -
Thanks @JonB for noticing the unchecked
deleteLater()but at this stage of the program I can at least be sure that theolmodelpointer is pointing to something because it was being used. Still, it's better to make sure the pointer is not null! The old selection modelolselmodis another thing. In fact, the code in github that I've linked previously doesn't mention theselectionModel()anywhere in the sources. But valgrind didn't show any major leak, so I'm not sure if it is being dealt aitomatically.@sairun
I wasn't sure whetherselectionModel()could potentially benullptrif, 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.
-
@sairun
I wasn't sure whetherselectionModel()could potentially benullptrif, 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.
Don't get me wrong @JonB. I prefer to do the checking. The issue is whether I care about
selectionModelor 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. -
Don't get me wrong @JonB. I prefer to do the checking. The issue is whether I care about
selectionModelor 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.@sairun
Yes, if you use selection then theQItemSelectionModelwill come into play. You should indeeddeleteordeleteLater()it as you are doing, else I think it may leak. I only meant that I do not know whetherview->selectionModel()is always guaranteed to be allocated and non-nullptr, if it can benullptrthen your original unprotected code would crash, so it's worth putting in the check. I think we are on the same page :) -
@sairun
Yes, if you use selection then theQItemSelectionModelwill come into play. You should indeeddeleteordeleteLater()it as you are doing, else I think it may leak. I only meant that I do not know whetherview->selectionModel()is always guaranteed to be allocated and non-nullptr, if it can benullptrthen your original unprotected code would crash, so it's worth putting in the check. I think we are on the same page :)@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
-
@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
@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.
-
@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
@Christian-Ehrlicher, what you mean is that per source code the
QItemSelectionModelis set as a child ofQAbstractItemModeland will be deleted when the latter is deleted? So I only have to deal with the model and not the selection model? -
@Christian-Ehrlicher, what you mean is that per source code the
QItemSelectionModelis set as a child ofQAbstractItemModeland will be deleted when the latter is deleted? So I only have to deal with the model and not the selection model?@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
-
@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
@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
QTableModelwithout referencing the QItemSelectionModel` as suggested, and so far everything is working as expected. I'll mark this as solved. -
S sairun has marked this topic as solved
-
@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
QTableModelwithout referencing the QItemSelectionModel` as suggested, and so far everything is working as expected. I'll mark this as solved.@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.