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 in QT6 and how to porting from QT5 to QT6
Forum Updated to NodeBB v4.3 + New Features

QML TreeView in QT6 and how to porting from QT5 to QT6

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
2 Posts 2 Posters 342 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.
  • M Offline
    M Offline
    manhpd9
    wrote on last edited by
    #1

    I am porting QT TreeView from QT5.15.2 to QT6.7.2. In Qt5.15.2 my TreeView run normal 3419fbc9-9d5c-493a-bce9-7521f5e9e60d-image.png
    But when i use QT6.7.2 some libraries are no longer supported.
    be000c82-f2f1-4e0f-b27e-425a7a71a865-image.png
    My main.qml in QT6.7.2

    import QtQuick
    import QtQuick.Controls
    
    ApplicationWindow {
        width: 800
        height: 600
        visible: true
    
        TreeView {
            id: treeView
            anchors.fill: parent
            anchors.margins: 10
            clip: true
    
            selectionModel: ItemSelectionModel {}
    
            // The model needs to be a QAbstractItemModel
            model: infoModel
    
            delegate: Item {
                implicitWidth: padding + label.x + label.implicitWidth + padding
                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
    
                // Rotate indicator when expanded by the user
                // (requires TreeView to have a selectionModel)
                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 ? palette.highlight : "black"
                    opacity: (treeView.alternatingRows && row % 2 !== 0) ? 0.3 : 0.1
                }
    
                Label {
                    id: indicator
                    x: padding + (depth * indentation)
                    anchors.verticalCenter: parent.verticalCenter
                    visible: isTreeNode && hasChildren
                    text: "▶"
    
                    TapHandler {
                        onSingleTapped: {
                            let index = treeView.index(row, column)
                            treeView.selectionModel.setCurrentIndex(index, ItemSelectionModel.NoUpdate)
                            treeView.toggleExpanded(row)
                        }
                    }
                }
    
                Label {
                    id: label
                    x: padding + (isTreeNode ? (depth + 1) * indentation : 0)
                    anchors.verticalCenter: parent.verticalCenter
                    width: parent.width - padding - x
                    clip: true
                    text: model.display
                }
            }
        }
    }
    
    

    My main.qml in QT5.15.2

    import QtQuick 2.4
    import QtQuick.Controls 1.4
    import QtQuick.Controls.Styles 1.4
    import QtQuick.Window 2.2
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("Tree Model")
    
        function expandAll(view, model) {
            for(var i=0; i < model.rowCount(); i++) {
                var index = model.index(i, 0)
                if (!view.isExpanded(index)) {
                    view.expand(index)
                }
                if (model.rowCount(index) > 0) {
                    expandChilds(view, model, index)
                }
            }
        }
        function expandChilds(view, model, parent) {
            for(var i=0; i < model.rowCount(parent); i++) {
                var index = model.index(i, 0, parent)
                if (!view.isExpanded(index)) {
                    view.expand(index)
                }
                if (model.rowCount(index) > 0) {
                    expandChilds(view, model, index)
                }
            }
        }
    
        Rectangle
        {
            id: rectId
            width: 400
            height: 400
            anchors.centerIn: parent
            border.color: "black"
            color: "white"
    
            TreeView
            {
    
                id: infoTreeView
                anchors.fill: parent
                model: infoModel
                selectionMode: SelectionMode.NoSelection
    
                frameVisible: false
                itemDelegate: Item {
                    Text {
                        anchors.fill: parent
                        elide: styleData.elideMode
                        text: styleData.value
                    }
                }
                horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
    
    
                TableViewColumn {
                    width: rectId.width / 2
                    role: "name"
                    title: "Name"
                }
    
                TableViewColumn {
                    width: rectId.width / 2
                    role: "value"
                    title: "Value"
                }
                Component.onCompleted: expandAll(infoTreeView, infoModel)
            }
        }
    }
    

    TreeModel.h

    // Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima).
    //
    // This file is part of eProsima Fast DDS Monitor.
    //
    // eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    //
    // eProsima Fast DDS Monitor is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the iapplied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with eProsima Fast DDS Monitor. If not, see <https://www.gnu.org/licenses/>.
    
    /**
     * @file TreeModel.hpp
     */
    
    #ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_TREEMODEL_H
    #define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_TREEMODEL_H
    
    #include <mutex>
    
    #include <QAbstractItemModel>
    #include <QModelIndex>
    #include <QVariant>
    #include "backend_types.h"
    #include "TreeItem.h"
    using json = backend::EntityInfo;
    
    namespace models {
    
    /**
     * @brief Abstract class that encapsulate the behaviour of entity a Data Model in Tree format
     *
     * A \c TreeModel store and manage a \c TreeItem that is the parent node of a full tree of Items.
     *
     * This Model is used by the view to represent values that contain values underneath.
     * The representation of these trees by the view will use the name of each entity, and will show all their
     * subentities under this name, each represented by its own name.
     *
     * The construction of these models is made by Data in json format, where each key is going to be
     * used as a name, and the values below will be added in a new item in the tree under it.
     * The last node (those without children nodes) is actually encapsulated in the father node in the \c VALUE column
     * inside its data.
     * This saves one node creation, and allows the view to represent in different columns those nodes with children
     * and the nodes that only represents a value.
     */
    class TreeModel : public QAbstractItemModel
    {
        Q_OBJECT
    
    public:
    
        //! Role names to allow queries to get some specific information from the Item
        enum TreeModelRoles
        {
            treeModelNameRole = Qt::UserRole + 1,   //! Role for attribute Name
            treeModelValueRole                      //! Role for attribute Value
        };
    
        /**
         *
         */
        explicit TreeModel(
            const json& data,
            QObject* parent = 0);
    
        explicit TreeModel(
            QObject* parent = 0);
    
        //! Delete and release all the information of items below
        ~TreeModel();
    
        //! Retrieve the data of one of the items indexed by \c index and its role \c role
        QVariant data(
            const QModelIndex& index,
            int role) const Q_DECL_OVERRIDE;
    
        //! Retrieve the flags of a node
        Qt::ItemFlags flags(
            const QModelIndex& index) const Q_DECL_OVERRIDE;
    
        //! Build an index giving row, column and parent
        QModelIndex index(
            int row,
            int column,
            const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
    
        //! Returns the index of the parend of the node indexed in \c index
        QModelIndex parent(
            const QModelIndex& index) const Q_DECL_OVERRIDE;
    
        //! Returns the number of rows in a node
        int rowCount(
            const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
    
        //! Returns the number of columns in a node
        int columnCount(
            const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
    
        //! Eliminates and release the parent node and all its children
        void clear();
    
        //! Clear the model and create a new tree with new data
        void update(
            json data);
    
        //! Return the role names of the values in nodes to acces them via \c data
        QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
    
        //! Retrieve the item in the position \c index
        TreeItem* get_item(
            const QModelIndex& index) const;
    
    signals:
    
        //! Signal that communicate that the model has been modified
        void updatedData();
    
    protected:
    
        /**
         * @brief Fill an internal node with data in json format
         *
         * It iterates over a json object, each key is created as a new subnode and the values
         * are used to fill this subnode with this same function.
         *
         * Go through the whole json and its subelements and change every array of elements by a dictionary
         * indexed by numbers starting in 0.
         * For the first element, adds an eappty row at the end to prevent the TreeView(*) error.
         *
         * (*) TreeView does not collapse correctly a subtree in case its last element is itself a subtree and
         * it is not collapsed.
         * @param json_data data in json format to fill the item
         * @param parent item to fill
         * @param _first wether is the parent element of the json (false only used in internal recursion)
         */
        static void setup_model_data(
            const json& json_data,
            TreeItem* parent,
            bool _first = true);
    
    private:
    
        //! Parent node of the items tree
        TreeItem* root_item_;
    
        mutable std::mutex update_mutex_;
    
    };
    
    } // namespace models
    
    #endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_TREEMODEL_H
    
    

    TreeModel.cpp

    // Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima).
    //
    // This file is part of eProsima Fast DDS Monitor.
    //
    // eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    //
    // eProsima Fast DDS Monitor is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the iapplied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with eProsima Fast DDS Monitor. If not, see <https://www.gnu.org/licenses/>.
    
    #include <QStringList>
    
    #include "TreeItem.h"
    #include "TreeModel.h"
    
    namespace models {
    
    TreeModel::TreeModel(
        const json& data,
        QObject* parent)
        : QAbstractItemModel(parent)
    {
        root_item_ = new TreeItem(QList<QString>() << "Name" << "Value");
        setup_model_data(data, root_item_);
    }
    
    TreeModel::TreeModel(
        QObject* parent)
        : QAbstractItemModel(parent)
    {
        root_item_ = new TreeItem(QList<QString>() << "Name" << "Value");
    }
    
    TreeModel::~TreeModel()
    {
        beginResetModel();
        root_item_->clear();
        endResetModel();
        delete root_item_;
    }
    
    int TreeModel::columnCount(
        const QModelIndex& parent) const
    {
        if (parent.isValid())
        {
            return get_item(parent)->column_count();
        }
        else
        {
            return root_item_->column_count();
        }
    }
    
    QVariant TreeModel::data(
        const QModelIndex& index,
        int role) const
    {
        if (!index.isValid())
        {
            return QVariant();
        }
    
        TreeItem* child_item = get_item(index);
    
        if (child_item != nullptr)
        {
            switch (role)
            {
            case treeModelNameRole:
                return child_item->get_item_name();
            case treeModelValueRole:
                return child_item->get_item_value();
            default:
                return QVariant();
            }
        }
    
        return QVariant();
    }
    
    Qt::ItemFlags TreeModel::flags(
        const QModelIndex& index) const
    {
        if (!index.isValid())
        {
            return Qt::NoItemFlags;
        }
    
        return QAbstractItemModel::flags(index);
    }
    
    QModelIndex TreeModel::index(
        int row,
        int column,
        const QModelIndex& parent) const
    {
        if (!hasIndex(row, column, parent))
        {
            return QModelIndex();
        }
    
        TreeItem* parent_item;
        if (!parent.isValid())
        {
            parent_item = root_item_;
        }
        else
        {
            parent_item = static_cast<TreeItem*>(parent.internalPointer());
        }
    
        TreeItem* child_item = parent_item->child_item(row);
        if (child_item)
        {
            return createIndex(row, column, child_item);
        }
        else
        {
            return QModelIndex();
        }
    }
    
    QModelIndex TreeModel::parent(
        const QModelIndex& index) const
    {
    
        TreeItem* parent_item = nullptr;
        TreeItem* child_item = nullptr;
    
        if (!index.isValid())
        {
            return QModelIndex();
        }
    
        if (parent_item == root_item_)
        {
            return QModelIndex();
        }
    
        if ((child_item = get_item(index)) != nullptr)
        {
            if ((parent_item = child_item->parent_item()) != nullptr)
            {
                return createIndex(parent_item->row(), 0, parent_item);
            }
        }
    
        return QModelIndex();
    }
    
    int TreeModel::rowCount(
        const QModelIndex& parent) const
    {
        TreeItem* parent_item;
        if (parent.column() > 0)
        {
            return 0;
        }
    
        if (!parent.isValid())
        {
            parent_item = root_item_;
        }
        else
        {
            parent_item = get_item(parent);
        }
    
        return parent_item->child_count();
    }
    
    QHash<int, QByteArray> TreeModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
    
        roles[treeModelNameRole] = "name";
        roles[treeModelValueRole] = "value";
    
        return roles;
    }
    
    TreeItem* TreeModel::get_item(
        const QModelIndex& index) const
    {
    
        TreeItem* item = nullptr;
    
        if (index.isValid())
        {
            item = static_cast<TreeItem*>(index.internalPointer());
            if (item != nullptr)
            {
                return item;
            }
        }
    
        return root_item_;
    }
    
    void TreeModel::setup_model_data(
        const json& json_data,
        TreeItem* parent,
        bool _first /* = true */)
    {
        QList<QString> data;
    
        bool last_child = false;
    
        json value;
    
        for (json::const_iterator it = json_data.begin(); it != json_data.end(); ++it)
        {
            data << QString::fromUtf8(it.key().c_str());
    
            if (it.value().is_primitive())
            {
                if (it.value().is_string())
                {
                    data << QString::fromUtf8(static_cast<std::string>(it.value()).c_str());
                    last_child = true;
                }
                else if (it.value().is_number())
                {
                    data << QString::number(static_cast<int>(it.value()));
                    last_child = true;
                }
                else if (it.value().is_boolean())
                {
                    data << (it.value() ? QString("true") : QString("false"));
                    last_child = true;
                }
                else
                {
                    data << "-";
                    last_child = true;
                }
            }
    
            TreeItem* current_child = new TreeItem(data, parent);
            if (!last_child)
            {
                setup_model_data(static_cast<json>(it.value()), current_child, false);
            }
    
            parent->append_child(current_child);
            data.clear();
    
    
            last_child = false;
        }
    
        // Add a final void element to avoid TreeView collapse fail
        if (_first)
        {
            TreeItem* eappty_child = new TreeItem(data, parent);
            parent->append_child(eappty_child);
        }
    }
    
    void TreeModel::clear()
    {
        root_item_->clear();
    }
    
    void TreeModel::update(
        json data)
    {
        std::unique_lock<std::mutex> lock(update_mutex_);
    
        beginResetModel();
        clear();
        setup_model_data(data, root_item_);
        endResetModel();
        emit updatedData();
    }
    
    } // namespace models
    
    
    1 Reply Last reply
    0
    • gfxxG Offline
      gfxxG Offline
      gfxx
      wrote on last edited by
      #2

      I have a similar problem whit treeview and opcua in qt6.7.2 ... no solutions for now.

      bkt

      1 Reply Last reply
      0

      • Login

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