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 like

    QString 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


  • Moderators

    Hi @hvoigt and Welcome,
    If I understood you correctly, you can use an Image component inside the delegate to set the icon ?



  • You need to do a combination of things:

    1. You'll need a custom model (trust me, I've tried to use built-in stuff and it's good for the basics only)
    2. 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 a QVariantMap 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();
    }
    

  • Moderators

    @hvoigt

    To return an image from QAbstractItemModel you can convert it to base64 and return a QString 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 the data(...) 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.



  • @cheezus @p3c0 FYI

    Since the question how to implement a TreeView with a QAbstractItemModel 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:

    https://github.com/hvoigt/qt-qml-treeview/tree/master


  • Moderators

    @hvoigt Thank you for sharing :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.