QML TreeView in QT6 and how to porting from QT5 to QT6
-
I am porting QT TreeView from QT5.15.2 to QT6.7.2. In Qt5.15.2 my TreeView run normal
But when i use QT6.7.2 some libraries are no longer supported.
My main.qml in QT6.7.2import 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