Memory management in Qt -- which is proper? - qt

PrintIntervalTableModel implements QAbstractTableModel
1) Am I supposed to assign a parent during creation?
PrintIntervalTableModel * model = new PrintIntervalTableModel(dataset, this);
ui.table->setModel(model);
or
2) Does the setModel call set the parent of the model to the view?
// Do not pass in a parent widget during construction...
// I have seen this in examples. Is it wrong, right, or a shaky practice?
PrintIntervalTableModel * model = new PrintIntervalTableModel(dataset);
ui.table->setModel(model);
If #2 is acceptable or even preferred, how do we know which function calls assign widgets to parents and which don't? It seems dangerous to just assume a call like setModel manages child memory if we have no objective evidence that it does.

Here is what the void QAbstractItemView::setModel(QAbstractItemModel *model) says:
The view does not take ownership of the model unless it is the model's parent object because the model may be shared between many different views.
So the view is not the parent of your model using setModel(...) function.
When you write PrintIntervalTableModel * model = new PrintIntervalTableModel(dataset, this); this refers to the class you are writing your code in, so there's no link with the view (in your example).
To define parent's objet, you can either put this in the constructor or call the function void QObject::setParent(QObject *parent), I don't think there is any other way to do it.

Related

How create a separate copy of a QQuickItem & render it on a different window

I have a QQuickItem fetched from C++ side like this.
QQuickItem * my_item = qmlEngine->rootObjects()[0]->findChild<QQuickItem*>("ItemObjectName");
my_item is valid & has all the properties set on to it.
Scenario
I have 2 windows which need this QQuickItem to be drawn on alterantively. I want to render this my_item to a different window. This works perfectly fine as long as I set the Parent of the my_item to the other window
// the_other_window is a QQuickWindow
QQuickWindow * the_other_window;
// here I set parent
my_item->setParentItem(the_other_window->contentItem());
This requires me to do setParentItem again back to my_item's original window otherwise it goes invisible on the original window. This is working but gives me unnecessary dependency. Instead I am trying to create a copy of the QQuickItem & do a setParentItem on that. By copying like this:
QQuickItem * item_copy = new QQuickItem(my_item);
Problem:
But this doesn't seem to create a copy of the QQuickItem & hence I don't see a copy of my_item on the_other_window.
Question:
All I want to know is, how can I create a valid copy a QQuickItem into another pointer say QQuickItem * item_copy & render it on a different window without affecting the visibility/state of the original QQuickItem?
The interface of QQuickItem doesn't provide clonability. If it did, then all its subclasses would have to reimplement a virtual clone() function.
Indeed, the QQuickItem derives from QObject which explicitly disables copy-like operations (copy constructor and assignment operator), so they're disabled in any QQuickItem-derived class as well. Even if you have a specific subclass of QQuickItem, which you think you know how to copy, you can't implement "real" copying for it.
The closest thing to do in the latter case is to instantiate a new, blank item of your type and manually copy all values of relevant properties from the old to the new instance. You can encapsulate code that in a copy function.

How to set text alignment for all the data in the tableView without using FOR loop?

I have create a tableView from database. Then, how to make set text alignment for all the data in this tableView? I do not want to use for loop to set each item in the tableView since it is time consuming.
The main code is as follows:
QSqlRelationalTableModel *model= new QSqlRelationalTableModel(NULL, db);
model->setTable(dbName);
model->select();
QTableView *tableView = new QTableView(NULL);
tableView->setModel(model);
Some may suggest to make a subclass of QSqlRelationalTableModel, but this also need a for loop to set all the data. Is there any other option? Thank you.
Use QIdentityProxyModel (since 4.8 - however, the idea is the same using a QAbstractProxyModel, the former is simply a convenience class that saves you time by allowing to reimplement only the methods you need). This approach avoids using a for loop since the data is set and returned at the moment it is being requested request on a per-element basis. In other words, instead of iterating over all the data and setting the required value (i.e. an imperative approach), you modify a method in the class that provides data to the view (more of a declarative approach), and the view pulls the data when necessary on its own.
To quote the docs:
http://doc.qt.io/qt-5/qidentityproxymodel.html
The QIdentityProxyModel class proxies its source model unmodified. Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the need to implement all data handling in the same class that creates the structure of the model, and can also be used to create re-usable components.
For our case, a possible implementation follows:
class StylingProxyModel : public QIdentityProxyModel
{
QVariant data(const QModelIndex &index, int role) const
{
if (role != Qt::TextAlignmentRole)
return QIdentityProxyModel::data(index, role);
return Qt::AlignCenter;
}
};
As you can see, the model will pass through itself the part of the data that doesn't match Qt::TextAlignmentRole, and return the desired value otherwise.
Set the QSqlRelationalTableModel as the source of this custom identity model, and set the proxy model to be the source for the view.
The "heavy artillery" option would be to subclass QStyledItemDelegate but I feel it's overkill for the case in question, being better suited for tasks that modify the view / delegate appearance in more profound ways than just setting text alignment.
See Set color to a QTableView row for further reading.

How to forward signals in a QAbstractItemModel wrapper model

I intend to create my own item model, derived from QAbstractItemModel. The model does not contain data but wraps some data repository. That repository emits signals after item(s) are insert, removed, renamed, etc.
Whenever something changes in the repository, my item model needs to forward those signals.
However the repository has standalone signals like void itemRemoved(int index); while QAbstractItemModel has begin/end pairs of protected functions (and signals) like beginInsertRows() and endInsertRows().
How should I handle this? E.g. I could connect a slot like the following to the repository's itemRemoved() signal:
void RepositoryItemRemoved(int i)
{
beginInsertRows(QModelIndex(), i, i);
endInsertRows();
}
Based on the above example: Is it valid to call beginInsertRows() / endInsertRows() sequently after a row has been inserted in the repository?
I've had a similar scenario, where the data is in a different object, and the model is just a wrapper, and only created if that data set is displayed in a view. I used a pointer to the model object in the data object, checking if it is null on insert operations, and if not call beginInsertRows() and endInsertRows() through it. Naturally, since those are protected, the data class would have to be declared a friend to the model class.
The documentation stresses that it is important to call beginInsertRows() before any data is inserted:
When reimplementing insertRows() in a subclass, you must call this
function before inserting data into the model's underlying data store...
...Otherwise, the views may end up in an invalid state.
You should test with a view, or alternatively, examine the actual implementation in the source.
I've had somewhat similar scenario as well, only in my case the Qt model wrapped the underlying model a little more literally: the underlying model contained sufficiently more data than the view had to know about. So I let the Qt model to contain its own list of small pieces of each underlying model's data item for the view/delegate to deal with. So the slots processing the updates from the underlying model looked like this:
void RepositoryItemRemoved(int i)
{
beginRemoveRows(QModelIndex(), i, i);
removeModelItem(i);
endRemoveRows();
}
Such design solved the problem of view's invalid state although it may be impractical for the use cases in which letting the Qt model contain its own items list would mean duplicating the sufficient amount of data being worked with.

How to reset a user-defined tree model in Qt

I have finally implemented my own tree model (inherited from QAbstractItemModel) for a QTreeView.
A blueprint of what I did can be found here:
http://www.trinitydesktop.org/docs/qt4/itemviews-simpletreemodel.html
So, I have:
the user-defined tree items, which are pure C++ (no Qt) and these are wrapped by
the TreeModel class which is inherited from QAbstractItemModel (like in the example link above).
I now have a generated tree hierarchy of tree items from (1.). This hierarchy has thousands of items, and I want to insert this hierarchy into my existing model at runtime.
How do I do that?
(All I have is the root-node to the c++ tree hierarchy as TreeItem pointer and a QModelIndex of the existing model where the "new sub-tree" has to be inserted)
I found modelAboutToBeReset(), modelReset(), and endResetModel() from here: http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#beginResetModel
But I don't know if these are the right functions, and, if they are, how to use them.
Any ideas?
You should call modelAboutToBeReset() before removing real items from your model. This call will "freeze" all views from requesting any data. After removing all real items you should call endResetModel() - it will unfreeze data requesting and force all connected views to update it content.
This is what i did:
void
TreeModel::addNewSubTreeToModel( TreeNode* t_rootOfNewTree, TreeNode* t_addNewSubTreeAsChildOfThisItem )
{
beginResetModel();
t_rootOfNewTree->setParent(t_addNewSubTreeAsChildOfThisItem);
t_addNewSubTreeAsChildOfThisItem->addChild(t_rootOfNewTree);
endResetModel();
}

Subclassing QStandardItemModel to avoid QAbstractItemModel

I'm implementing a Model/View for a tree like structure, and I've decided to try the QStandardItemModel on which I want to wrap on it a specific class, (which I call here "appSpecificClass").
Basically, I want part of that class (like names, or some data), to be shown in the model, and when I change the model (in edit role, or drag and drop), I want that to have consequences on the appSpecificClass (which is, when I change a name that is showing on the model, the name on the object associated with the model's item of the appSpecificClass also changes).
So, I started from subclassing the QStandardItem by a appSpecificItem, which only has a pointer to the appSpecificClass. When I construct the appSpecificItem, the text and icons are called from appSpecificClass and everything works fine.
However, when change data from appSpecificItem, naturally it does not change the appSpecificClass, because so far I didn't found any way of interacting with the appSpecificItem's pointer via overloading a virtual function (or else)
Does anyone knows how to do this/if this is possible? What can I do such that if for instance the signal
QStandardItemModel::itemChanged ( QStandardItem * item )
is emitted, I can change a the appSpecificItem's pointer.
If not, is there any good tutorial about implementing a Model from scratch? I've tried myself some, but it is not an easy task. Ideally I would like a QStandardItemModel like model, but a little more abstraction on it (such that I can put my appSpecificClass on it).

Resources