Add more than text to TreeView delegates? (like an extra Icon, ...)
-
Hi,
I am trying to use a TreeView and have multiple things in the delegate. E.g. in some rows I would like to put an Icon. But from the example it seems there is only
styleData.value
available. I used to do that with different roles on a ListView but AFAICS they are used for the columns in the TreeView. Implementing a method likeQString getIcon(const QModelIndex &index);
which returns me the Icon is a workaround, but then I loose the property binding. So when I update my Model I would have to trigger the update of the display manually right?
Is there a better way to extra things like icons to the TreeView delegates?
Thanks, Heiko
-
You need to do a combination of things:
- You'll need a custom model (trust me, I've tried to use built-in stuff and it's good for the basics only)
- Set custom roles (see roleNames())
Then your TableViewColumn will have a delegate with a role of (say) "compositeData" which you can then use for loading your image.
Something like:
TableViewColumn { role: "compositeData" delegate: Image{source: styleData.value.iconUrl} // Text{text: styleData.value.text} } ... QHash<int,QString> roleNames() const { QHash<int,QString> ret; ret[Qt::UserRole] = "compositeData" return ret; } QVariant data(...) { if(role == Qt::UserRole) return QVariantMap(...) }
-
First of all: Thanks for all the quick replies.
@p3c0: Hi, thanks for the welcome :) My question was more geared towards how to transport which icon should be drawn from the model (c++) to QML.
@cheezus: So if I understand correctly I should implement a
QAbstractItemModel
and use that to return aQVariantMap
in the data method. Is there any good example how to assemble the parent child stuff for the TreeView? At the moment I am using the QStandardItemModel since that is what I found in some example. I just searched and found this:http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
If I setup the model like there I should be able to use it with the TreeView in QML right?
-
@hvoigt Yep. I use the following:
#ifndef TREEMODEL_HPP #define TREEMODEL_HPP #include <QAbstractItemModel> #include <memory> #include <vector> template <typename T> class TreeModel : public QAbstractItemModel { public: explicit TreeModel(QObject * parent=0):QAbstractItemModel(parent){} void reset() { beginResetModel(); updateRootNodes(); endResetModel(); } protected: void updateRootNodes() { m_rootNodes = getRootNodes(); } struct Node; using NodeVec = std::vector<std::unique_ptr<Node>>; struct Node { Node(std::shared_ptr<T> const & value, Node*parent,int row): value(value), parent(parent), row(row){} std::shared_ptr<T> value; Node * parent = nullptr; int row = -1; NodeVec children; }; virtual NodeVec getRootNodes() = 0; private: std::vector<std::unique_ptr<Node>> m_rootNodes; protected: QModelIndex index(int row, int column, QModelIndex const & parent = QModelIndex()) const override; QModelIndex parent(QModelIndex const & index) const override; int rowCount(QModelIndex const & parent) const override; }; #include "TreeModel.ipp" #endif // TREEMODEL_HPP
// TreeModel.ipp template<typename T> QModelIndex TreeModel<T>::index(int row, int column, QModelIndex const & parent) const { if(!parent.isValid()) return createIndex(row,column,m_rootNodes[row].get()); else { auto parentNode = reinterpret_cast<Node*>(parent.internalPointer()); return createIndex(row,column,parentNode->children[row].get()); } } template<typename T> QModelIndex TreeModel<T>::parent(QModelIndex const & index) const { if(!index.isValid()) return QModelIndex(); auto node = reinterpret_cast<Node*>(index.internalPointer()); if(!node->parent) return QModelIndex(); else return createIndex(node->parent->row,0,node->parent); } template<typename T> int TreeModel<T>::rowCount(QModelIndex const & parent) const { if(!parent.isValid()) return m_rootNodes.size(); auto node = reinterpret_cast<Node*>(parent.internalPointer()); return node->children.size(); }
-
To return an image from
QAbstractItemModel
you can convert it to base64 and return aQString
and to decode it on QML side something like this should work:Image { source: "data:image/png;base64," + model.imagedata }
If I setup the model like there I should be able to use it with the TreeView in QML right?
Yes. Just make sure you re-implement
roleNames
.
https://forum.qt.io/topic/56497/request-treeview-c-model-to-qml-example
https://forum.qt.io/topic/56653/example-of-correctly-operating-c-model-with-qml-treeview/
https://forum.qt.io/topic/56099/solved-new-treeview-does-not-connect-to-c-model -
Got it. Its working for me now. Marked as solved.
@cheezus: The bit with returning the
QVariantMap()
from thedata(...)
method was what solved my question.@p3c0: Thanks for the links they helped to implement the
QAbstractItemModel
and avoid the seemingly common pitfalls as well. The bit with base64 encoding the icon is an interesting one. I am currently just using an Image Path from the resources. But that might come in handy sometime.Thanks a lot, this was awesome.
-
Since the question how to implement a
TreeView
with aQAbstractItemModel
seems to have been asked a few times I took the opportunity and adapted the "Simple Tree Model Example" to QML. You can find it on my GitHub: