Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML TreeView with custom delegate
Forum Updated to NodeBB v4.3 + New Features

QML TreeView with custom delegate

Scheduled Pinned Locked Moved Solved QML and Qt Quick
6 Posts 3 Posters 742 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.
  • O Offline
    O Offline
    oYASo
    wrote on 15 Jan 2025, 01:56 last edited by oYASo
    #1

    Hi!

    I'm trying to work with QML TreeView in Qt 6.8, but I'm having issues and can't make progress.
    I want to create a hierarchy like the one shown in the screenshot, which includes:

    • an expand/collapse indicator
    • an icon
    • text
    • the number of items (for root nodes) or the size (for leaf nodes)

    2025-01-15_04-51-50.png

    To start, I'm trying to solve a simple problem: aligning the size value to the right edge. However, any attempts to use anchors result in the entire list shifting somewhere, and I can't fix it.

    The second problem is: how can I add an image?

    Does anyone have examples of using TreeView with custom delegates? I can customize them perfectly for ListView, but I can't figure out how they work with TreeView.

    Thanks for any advice!

    Right now my code looks like this:

    import QtQuick
    import QtQuick.Controls
    import Qt.labs.qmlmodels
    
    Item {
        id: root
        width: 260
        height: 700
    
        TreeView {
            id: treeView
            anchors.fill: parent
    
            model: assetModel
            selectionModel: ItemSelectionModel {
                model: treeView.model
            }
    
            delegate: DelegateChooser {
                id: viewDelegate
    
                DelegateChoice {
                    id: nameDelegateChoice
                    column: 0
                    delegate: TreeViewDelegate {
                        id: nameDelegate
                        implicitWidth: 150
                        background: Rectangle {
                            id: backgroundRectangle
                            color: "transparent"
                        }
                        contentItem: Row {
                            id: row
                            Image {
                                source: "../../images/svg-folder.svg"
                                width: 20
                                height: 20
                            }
    
                            Label {
                                text: model.display
                                color: "white"
                                font.pixelSize: 14
                                font.family: "Roboto Medium"
                            }
                        }
                    }
                }
                DelegateChoice {
                    id: sizeDelegateChoice
                    column: 1
                    delegate: TreeViewDelegate {
                        id: treeViewDelegate
                        background: Rectangle {
                            id: backgroundRectangle2
                            color: "transparent"
                        }
                        contentItem: Row {
                            id: row2
                            Label {
                                text: model.display
                                color: "white"
                                font.pixelSize: 14
                                font.family: "Roboto Medium"
                            }
                        }
                    }
                }
            }
        }
    }
    

    Model:

    #include "AssetModel.hpp"
    #include <QVariantList>
    #include "AssetItem.hpp"
    
    AssetModel::AssetModel(QObject *parent)
        : QAbstractItemModel{parent}
        , m_rootItem(std::make_unique<AssetItem>("RootDir", AssetItem::Type::Directory))
    {
        setupModelData();
    }
    
    AssetModel::~AssetModel() = default;
    
    QVariant AssetModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid()) {
            return QVariant();
        }
    
        AssetItem *item = static_cast<AssetItem *>(index.internalPointer());
        if (role == Qt::DisplayRole) {
            return item->data(index.column());
        }
    
        return QVariant();
    }
    
    Qt::ItemFlags AssetModel::flags(const QModelIndex &index) const
    {
        if (!index.isValid()) {
            return Qt::NoItemFlags;
        }
    
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    }
    
    QVariant AssetModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
        return orientation == Qt::Horizontal && role == Qt::DisplayRole ? m_rootItem->data(section)
                                                                        : QVariant{};
    }
    
    QModelIndex AssetModel::index(int row, int column, const QModelIndex &parent) const
    {
        if (!hasIndex(row, column, parent)) {
            return QModelIndex();
        }
    
        AssetItem *parentItem = parent.isValid() ? static_cast<AssetItem *>(parent.internalPointer())
                                                 : m_rootItem.get();
        AssetItem *childItem = parentItem->child(row);
    
        return childItem ? createIndex(row, column, childItem) : QModelIndex();
    }
    
    QModelIndex AssetModel::parent(const QModelIndex &index) const
    {
        if (!index.isValid()) {
            return QModelIndex();
        }
    
        AssetItem *childItem = static_cast<AssetItem *>(index.internalPointer());
        AssetItem *parentItem = childItem->parentItem();
    
        if (parentItem == m_rootItem.get()) {
            return QModelIndex();
        }
    
        return createIndex(parentItem->row(), 0, parentItem);
    }
    
    int AssetModel::rowCount(const QModelIndex &parent) const
    {
        AssetItem *parentItem = parent.isValid() ? static_cast<AssetItem *>(parent.internalPointer())
                                                 : m_rootItem.get();
        return parentItem->childCount();
    }
    
    int AssetModel::columnCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent)
        return 2; // Columns: name and size
    }
    
    // void AssetModel::setupModelData(const QList<QStringView> &lines, AssetItem *parent)
    void AssetModel::setupModelData()
    {
        // Example
        auto dir1 = std::make_unique<AssetItem>("Uploads", AssetItem::Type::Directory, m_rootItem.get());
        dir1->appendChild(
            std::make_unique<AssetItem>("logo.png", AssetItem::Type::File, dir1.get(), 1024));
        dir1->appendChild(
            std::make_unique<AssetItem>("Arial.ttf", AssetItem::Type::File, dir1.get(), 4332523));
        dir1->appendChild(
            std::make_unique<AssetItem>("Hello.zip", AssetItem::Type::File, dir1.get(), 3245452));
        dir1->appendChild(
            std::make_unique<AssetItem>("Intro.mp3", AssetItem::Type::File, dir1.get(), 53245132));
        dir1->appendChild(
            std::make_unique<AssetItem>("mem.gif", AssetItem::Type::File, dir1.get(), 35353));
        dir1->appendChild(
            std::make_unique<AssetItem>("File.xml", AssetItem::Type::File, dir1.get(), 77332));
    
        auto dir2 = std::make_unique<AssetItem>("Assets", AssetItem::Type::Directory, m_rootItem.get());
        dir2->appendChild(
            std::make_unique<AssetItem>("avatar_1.png", AssetItem::Type::File, dir2.get(), 43245));
        dir2->appendChild(
            std::make_unique<AssetItem>("avatar_2.png", AssetItem::Type::File, dir2.get(), 73412));
    
        m_rootItem->appendChild(std::move(dir1));
        m_rootItem->appendChild(std::move(dir2));
    }
    
    

    And TreeView looks like this:
    2025-01-15_04-57-36.png

    B 1 Reply Last reply 15 Jan 2025, 14:12
    0
    • O Offline
      O Offline
      oYASo
      wrote on 21 Jan 2025, 13:49 last edited by
      #6

      Hi!

      Thank you for your responses!

      Unfortunately, the documentation for TreeView is not very detailed, and examples are quite scarce. I followed your advice and dug deeper into how the delegate works for TreeView. As a result, I managed to achieve exactly what I needed, as shown in the original screenshot.

      To help others understand this topic more easily, I’ll share my code below.

      Key ideas:

      • The entire view layout can be customized using the delegate. There’s no need to come up with complex solutions like DelegateChooser, which I had been trying earlier.
      • You can use the column and row variables to determine which row or column is being processed.
      • As mentioned earlier, to align text, you should use horizontalAlignment.
      • You need to align the row yourself (make indents depending on the nesting).
      import QtQuick
      import QtQuick.Controls
      import Qt5Compat.GraphicalEffects
      
      Item {
          id: root
          width: 260
          height: 700
      
          TreeView {
              id: treeView
              anchors.fill: parent
              anchors.margins: 10
              clip: true
      
              model: assetModel
              selectionModel: ItemSelectionModel {
                  model: treeView.model
              }
      
              delegate: Item {
                  implicitWidth: column === 0 ? root.width * 2/3 - padding * 2 : root.width * 1/3 - padding * 2
                  implicitHeight: label.implicitHeight * 1.5
      
                  readonly property real indentation: 20
                  readonly property real padding: 5
      
                  // Assigned to by TreeView:
                  required property TreeView treeView
                  required property bool isTreeNode
                  required property bool expanded
                  required property int hasChildren
                  required property int depth
                  required property int row
                  required property int column
                  required property bool current
      
                  property Animation indicatorAnimation: NumberAnimation {
                      target: indicator
                      property: "rotation"
                      from: expanded ? 0 : 90
                      to: expanded ? 90 : 0
                      duration: 100
                      easing.type: Easing.OutQuart
                  }
                  TableView.onPooled: indicatorAnimation.complete()
                  TableView.onReused: if (current) indicatorAnimation.start()
                  onExpandedChanged: indicator.rotation = expanded ? 90 : 0
      
                  Rectangle {
                      id: background
                      anchors.fill: parent
                      color: row === treeView.currentRow ? "#0085F8" : "transparent"
                  }
      
                  Label {
                      id: indicator
                      x: padding + (depth * indentation) + 5
                      anchors.verticalCenter: parent.verticalCenter
                      visible: isTreeNode && hasChildren
                      text: "▶"
                      color: "white"
      
                      TapHandler {
                          onSingleTapped: {
                              let index = treeView.index(row, column)
                              treeView.selectionModel.setCurrentIndex(index, ItemSelectionModel.NoUpdate)
                              treeView.toggleExpanded(row)
                          }
                      }
                  }
      
                  Image {
                      id: image
                      x: (isTreeNode ? (depth + 1) * indentation : 0)
                      anchors.verticalCenter: parent.verticalCenter
                      width: 13
                      height: 13
                      source:  hasChildren ? "../../images/svg-folder.svg" : "../../images/svg-file.svg"
                      visible: column === 0 ? true : false
      
                      ColorOverlay {
                          source: image
                          anchors.fill: image
                          color: "white"
                      }
                  }
      
                  Label {
                      id: label
                      x: image.x + image.width + 5
                      anchors.verticalCenter: parent.verticalCenter
                      width: parent.width - padding - x
                      clip: true
                      text: model.display
                      color: column === 0 ? "white" : "#ABABAB"
                      font.pixelSize: column === 0 ? 14 : 10
                      horizontalAlignment: isTreeNode ? Text.AlignLeft : Text.AlignRight
                      rightPadding: 10
                      font.family: "Roboto Medium"
                  }
              }
      
              MouseArea {
                  id: menuMouseArea
                  anchors.fill: parent
                  acceptedButtons: Qt.RightButton
      
                  Connections {
                      target: menuMouseArea
                      onClicked: {
                          menu.open()
                          menu.x = menuMouseArea.mouseX
                          menu.y = menuMouseArea.mouseY
                      }
                  }
              }
          }
      
          Menu {
              id: menu
              width: 150
              leftPadding: 5
              font.family: "Roboto Medium"
      
              palette.window: "#1f1f1f"
              palette.text: "white"
              palette.windowText: "white"
              palette.light: "#898989"
      
              MenuItem {
                  text: "Rename"
                  icon.source: "../../images/svg-edit.svg"
                  icon.width: 14
                  icon.height: 14
              }
              MenuItem {
                  text: "Delete"
                  icon.source: "../../images/svg-trash.svg"
                  icon.width: 14
                  icon.height: 14
              }
          }
      }
      
      

      Now it looks like this:
      2025-01-21_16-47-47.png

      Thank you all!

      1 Reply Last reply
      2
      • O oYASo
        15 Jan 2025, 01:56

        Hi!

        I'm trying to work with QML TreeView in Qt 6.8, but I'm having issues and can't make progress.
        I want to create a hierarchy like the one shown in the screenshot, which includes:

        • an expand/collapse indicator
        • an icon
        • text
        • the number of items (for root nodes) or the size (for leaf nodes)

        2025-01-15_04-51-50.png

        To start, I'm trying to solve a simple problem: aligning the size value to the right edge. However, any attempts to use anchors result in the entire list shifting somewhere, and I can't fix it.

        The second problem is: how can I add an image?

        Does anyone have examples of using TreeView with custom delegates? I can customize them perfectly for ListView, but I can't figure out how they work with TreeView.

        Thanks for any advice!

        Right now my code looks like this:

        import QtQuick
        import QtQuick.Controls
        import Qt.labs.qmlmodels
        
        Item {
            id: root
            width: 260
            height: 700
        
            TreeView {
                id: treeView
                anchors.fill: parent
        
                model: assetModel
                selectionModel: ItemSelectionModel {
                    model: treeView.model
                }
        
                delegate: DelegateChooser {
                    id: viewDelegate
        
                    DelegateChoice {
                        id: nameDelegateChoice
                        column: 0
                        delegate: TreeViewDelegate {
                            id: nameDelegate
                            implicitWidth: 150
                            background: Rectangle {
                                id: backgroundRectangle
                                color: "transparent"
                            }
                            contentItem: Row {
                                id: row
                                Image {
                                    source: "../../images/svg-folder.svg"
                                    width: 20
                                    height: 20
                                }
        
                                Label {
                                    text: model.display
                                    color: "white"
                                    font.pixelSize: 14
                                    font.family: "Roboto Medium"
                                }
                            }
                        }
                    }
                    DelegateChoice {
                        id: sizeDelegateChoice
                        column: 1
                        delegate: TreeViewDelegate {
                            id: treeViewDelegate
                            background: Rectangle {
                                id: backgroundRectangle2
                                color: "transparent"
                            }
                            contentItem: Row {
                                id: row2
                                Label {
                                    text: model.display
                                    color: "white"
                                    font.pixelSize: 14
                                    font.family: "Roboto Medium"
                                }
                            }
                        }
                    }
                }
            }
        }
        

        Model:

        #include "AssetModel.hpp"
        #include <QVariantList>
        #include "AssetItem.hpp"
        
        AssetModel::AssetModel(QObject *parent)
            : QAbstractItemModel{parent}
            , m_rootItem(std::make_unique<AssetItem>("RootDir", AssetItem::Type::Directory))
        {
            setupModelData();
        }
        
        AssetModel::~AssetModel() = default;
        
        QVariant AssetModel::data(const QModelIndex &index, int role) const
        {
            if (!index.isValid()) {
                return QVariant();
            }
        
            AssetItem *item = static_cast<AssetItem *>(index.internalPointer());
            if (role == Qt::DisplayRole) {
                return item->data(index.column());
            }
        
            return QVariant();
        }
        
        Qt::ItemFlags AssetModel::flags(const QModelIndex &index) const
        {
            if (!index.isValid()) {
                return Qt::NoItemFlags;
            }
        
            return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
        }
        
        QVariant AssetModel::headerData(int section, Qt::Orientation orientation, int role) const
        {
            return orientation == Qt::Horizontal && role == Qt::DisplayRole ? m_rootItem->data(section)
                                                                            : QVariant{};
        }
        
        QModelIndex AssetModel::index(int row, int column, const QModelIndex &parent) const
        {
            if (!hasIndex(row, column, parent)) {
                return QModelIndex();
            }
        
            AssetItem *parentItem = parent.isValid() ? static_cast<AssetItem *>(parent.internalPointer())
                                                     : m_rootItem.get();
            AssetItem *childItem = parentItem->child(row);
        
            return childItem ? createIndex(row, column, childItem) : QModelIndex();
        }
        
        QModelIndex AssetModel::parent(const QModelIndex &index) const
        {
            if (!index.isValid()) {
                return QModelIndex();
            }
        
            AssetItem *childItem = static_cast<AssetItem *>(index.internalPointer());
            AssetItem *parentItem = childItem->parentItem();
        
            if (parentItem == m_rootItem.get()) {
                return QModelIndex();
            }
        
            return createIndex(parentItem->row(), 0, parentItem);
        }
        
        int AssetModel::rowCount(const QModelIndex &parent) const
        {
            AssetItem *parentItem = parent.isValid() ? static_cast<AssetItem *>(parent.internalPointer())
                                                     : m_rootItem.get();
            return parentItem->childCount();
        }
        
        int AssetModel::columnCount(const QModelIndex &parent) const
        {
            Q_UNUSED(parent)
            return 2; // Columns: name and size
        }
        
        // void AssetModel::setupModelData(const QList<QStringView> &lines, AssetItem *parent)
        void AssetModel::setupModelData()
        {
            // Example
            auto dir1 = std::make_unique<AssetItem>("Uploads", AssetItem::Type::Directory, m_rootItem.get());
            dir1->appendChild(
                std::make_unique<AssetItem>("logo.png", AssetItem::Type::File, dir1.get(), 1024));
            dir1->appendChild(
                std::make_unique<AssetItem>("Arial.ttf", AssetItem::Type::File, dir1.get(), 4332523));
            dir1->appendChild(
                std::make_unique<AssetItem>("Hello.zip", AssetItem::Type::File, dir1.get(), 3245452));
            dir1->appendChild(
                std::make_unique<AssetItem>("Intro.mp3", AssetItem::Type::File, dir1.get(), 53245132));
            dir1->appendChild(
                std::make_unique<AssetItem>("mem.gif", AssetItem::Type::File, dir1.get(), 35353));
            dir1->appendChild(
                std::make_unique<AssetItem>("File.xml", AssetItem::Type::File, dir1.get(), 77332));
        
            auto dir2 = std::make_unique<AssetItem>("Assets", AssetItem::Type::Directory, m_rootItem.get());
            dir2->appendChild(
                std::make_unique<AssetItem>("avatar_1.png", AssetItem::Type::File, dir2.get(), 43245));
            dir2->appendChild(
                std::make_unique<AssetItem>("avatar_2.png", AssetItem::Type::File, dir2.get(), 73412));
        
            m_rootItem->appendChild(std::move(dir1));
            m_rootItem->appendChild(std::move(dir2));
        }
        
        

        And TreeView looks like this:
        2025-01-15_04-57-36.png

        B Offline
        B Offline
        Bob64
        wrote on 15 Jan 2025, 14:12 last edited by Bob64
        #2

        @oYASo said in QML TreeView with custom delegate:

        To start, I'm trying to solve a simple problem: aligning the size value to the right edge. However, any attempts to use anchors result in the entire list shifting somewhere, and I can't fix it.

        I found it a bit tricky to unpick what it is you are asking. It looks like the issue mentioned above is not illustrated in the code you provided - correct?

        So the main issue you discuss is the image one. I am not saying that what you have done is incorrect but in my projects I have always included images in my resources rather than trying to find them as relative paths. My source: settings then look something like this:

        Image {
            source: "qrc:///icons/arrow-up.svg"
        }
        

        This corresponds to a line like this in my qml.qrc:

            <file>icons/arrow-up.svg</file>
        

        The actual image file in my project is at the path specified above, relative to the location of the qml.qrc.

        Something looks odd to me in your DelegateChooser code, though it might be because I don't have much experience with using this component. I thought that the DelegateChooser was supposed to define a role name for the role that will be used to select the choice, and that the DelegateChoices would each specify a roleValue to determine which value of the role they should correspond to. I'm also not entirely sure that you are using columns correctly in your model and view but again it could just be my ignorance.

        To make progress, I would simplify this as much as possible - perhaps forget about the delegate choice in the first instance, and focus on getting the image displaying.

        O 1 Reply Last reply 15 Jan 2025, 17:40
        1
        • B Bob64
          15 Jan 2025, 14:12

          @oYASo said in QML TreeView with custom delegate:

          To start, I'm trying to solve a simple problem: aligning the size value to the right edge. However, any attempts to use anchors result in the entire list shifting somewhere, and I can't fix it.

          I found it a bit tricky to unpick what it is you are asking. It looks like the issue mentioned above is not illustrated in the code you provided - correct?

          So the main issue you discuss is the image one. I am not saying that what you have done is incorrect but in my projects I have always included images in my resources rather than trying to find them as relative paths. My source: settings then look something like this:

          Image {
              source: "qrc:///icons/arrow-up.svg"
          }
          

          This corresponds to a line like this in my qml.qrc:

              <file>icons/arrow-up.svg</file>
          

          The actual image file in my project is at the path specified above, relative to the location of the qml.qrc.

          Something looks odd to me in your DelegateChooser code, though it might be because I don't have much experience with using this component. I thought that the DelegateChooser was supposed to define a role name for the role that will be used to select the choice, and that the DelegateChoices would each specify a roleValue to determine which value of the role they should correspond to. I'm also not entirely sure that you are using columns correctly in your model and view but again it could just be my ignorance.

          To make progress, I would simplify this as much as possible - perhaps forget about the delegate choice in the first instance, and focus on getting the image displaying.

          O Offline
          O Offline
          oYASo
          wrote on 15 Jan 2025, 17:40 last edited by
          #3

          @Bob64 Thank you for your response, and sorry for the unclear explanation of my issue.

          The first problem I’m facing is how to align content to the left or right in a TreeView column. The first screenshot in my post shows how I’d like it to look, while the second screenshot shows the current state. On the second screenshot, you can see that the file size is aligned to the left, but I need it to be aligned to the right.

          I tried solving this issue by using alignment in the model, specifically with the TextAlignmentRole, but it seems like this doesn’t work.

          I also attempted to achieve this by aligning the contentItem in the delegate, but this didn’t work either.

          So, my initial question is: how can I align the second column in a TreeView to the right?

          1 Reply Last reply
          0
          • B Offline
            B Offline
            Bob64
            wrote on 16 Jan 2025, 10:46 last edited by
            #4

            OK, thanks for the clarification.

            It seems like this should not be too difficult. If I understand correctly now, the tree has two columns and second delegate choice is for the second column.

            I would probably start by removing the Row from the content item of the second column as it doesn't seem to be serving much purpose and will get in the way of using other layout mechanisms like anchors. I would replace it with an Item that fills the available width. You should then be able to anchor the text to the right of the containing item.

            1 Reply Last reply
            1
            • G Offline
              G Offline
              GrecKo
              Qt Champions 2018
              wrote on 16 Jan 2025, 13:18 last edited by GrecKo
              #5

              TreeView and TreeViewDelegate ignores the TextAlignmentRole.

              Getting rid of the Row and using the Label with horizontalAlignment should do the trick:

              delegate: TreeViewDelegate {
                  background: null // there's no point in using a Rectangle with a transparent background
                  contentItem: Label {
                      text: model.display
                      horizontalAlignment: Text.AlignRight
                      color: "white"
                      font.pixelSize: 14
                      font.family: "Roboto Medium"
                  }
              }
              
              1 Reply Last reply
              2
              • O Offline
                O Offline
                oYASo
                wrote on 21 Jan 2025, 13:49 last edited by
                #6

                Hi!

                Thank you for your responses!

                Unfortunately, the documentation for TreeView is not very detailed, and examples are quite scarce. I followed your advice and dug deeper into how the delegate works for TreeView. As a result, I managed to achieve exactly what I needed, as shown in the original screenshot.

                To help others understand this topic more easily, I’ll share my code below.

                Key ideas:

                • The entire view layout can be customized using the delegate. There’s no need to come up with complex solutions like DelegateChooser, which I had been trying earlier.
                • You can use the column and row variables to determine which row or column is being processed.
                • As mentioned earlier, to align text, you should use horizontalAlignment.
                • You need to align the row yourself (make indents depending on the nesting).
                import QtQuick
                import QtQuick.Controls
                import Qt5Compat.GraphicalEffects
                
                Item {
                    id: root
                    width: 260
                    height: 700
                
                    TreeView {
                        id: treeView
                        anchors.fill: parent
                        anchors.margins: 10
                        clip: true
                
                        model: assetModel
                        selectionModel: ItemSelectionModel {
                            model: treeView.model
                        }
                
                        delegate: Item {
                            implicitWidth: column === 0 ? root.width * 2/3 - padding * 2 : root.width * 1/3 - padding * 2
                            implicitHeight: label.implicitHeight * 1.5
                
                            readonly property real indentation: 20
                            readonly property real padding: 5
                
                            // Assigned to by TreeView:
                            required property TreeView treeView
                            required property bool isTreeNode
                            required property bool expanded
                            required property int hasChildren
                            required property int depth
                            required property int row
                            required property int column
                            required property bool current
                
                            property Animation indicatorAnimation: NumberAnimation {
                                target: indicator
                                property: "rotation"
                                from: expanded ? 0 : 90
                                to: expanded ? 90 : 0
                                duration: 100
                                easing.type: Easing.OutQuart
                            }
                            TableView.onPooled: indicatorAnimation.complete()
                            TableView.onReused: if (current) indicatorAnimation.start()
                            onExpandedChanged: indicator.rotation = expanded ? 90 : 0
                
                            Rectangle {
                                id: background
                                anchors.fill: parent
                                color: row === treeView.currentRow ? "#0085F8" : "transparent"
                            }
                
                            Label {
                                id: indicator
                                x: padding + (depth * indentation) + 5
                                anchors.verticalCenter: parent.verticalCenter
                                visible: isTreeNode && hasChildren
                                text: "▶"
                                color: "white"
                
                                TapHandler {
                                    onSingleTapped: {
                                        let index = treeView.index(row, column)
                                        treeView.selectionModel.setCurrentIndex(index, ItemSelectionModel.NoUpdate)
                                        treeView.toggleExpanded(row)
                                    }
                                }
                            }
                
                            Image {
                                id: image
                                x: (isTreeNode ? (depth + 1) * indentation : 0)
                                anchors.verticalCenter: parent.verticalCenter
                                width: 13
                                height: 13
                                source:  hasChildren ? "../../images/svg-folder.svg" : "../../images/svg-file.svg"
                                visible: column === 0 ? true : false
                
                                ColorOverlay {
                                    source: image
                                    anchors.fill: image
                                    color: "white"
                                }
                            }
                
                            Label {
                                id: label
                                x: image.x + image.width + 5
                                anchors.verticalCenter: parent.verticalCenter
                                width: parent.width - padding - x
                                clip: true
                                text: model.display
                                color: column === 0 ? "white" : "#ABABAB"
                                font.pixelSize: column === 0 ? 14 : 10
                                horizontalAlignment: isTreeNode ? Text.AlignLeft : Text.AlignRight
                                rightPadding: 10
                                font.family: "Roboto Medium"
                            }
                        }
                
                        MouseArea {
                            id: menuMouseArea
                            anchors.fill: parent
                            acceptedButtons: Qt.RightButton
                
                            Connections {
                                target: menuMouseArea
                                onClicked: {
                                    menu.open()
                                    menu.x = menuMouseArea.mouseX
                                    menu.y = menuMouseArea.mouseY
                                }
                            }
                        }
                    }
                
                    Menu {
                        id: menu
                        width: 150
                        leftPadding: 5
                        font.family: "Roboto Medium"
                
                        palette.window: "#1f1f1f"
                        palette.text: "white"
                        palette.windowText: "white"
                        palette.light: "#898989"
                
                        MenuItem {
                            text: "Rename"
                            icon.source: "../../images/svg-edit.svg"
                            icon.width: 14
                            icon.height: 14
                        }
                        MenuItem {
                            text: "Delete"
                            icon.source: "../../images/svg-trash.svg"
                            icon.width: 14
                            icon.height: 14
                        }
                    }
                }
                
                

                Now it looks like this:
                2025-01-21_16-47-47.png

                Thank you all!

                1 Reply Last reply
                2
                • O oYASo has marked this topic as solved on 22 Jan 2025, 12:04

                4/6

                16 Jan 2025, 10:46

                • Login

                • Login or register to search.
                4 out of 6
                • First post
                  4/6
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved