记录 QML TreeView 使用
参考链接:
代码如下:
TreeNode.h
//TreeNode.h
#include <QObject>
#include <QList>
#include <QVariant>
#include <QStringList>
#include <QModelIndex>
class TreeNode
{
public:
TreeNode(const QList<QVariant> &data, TreeNode *parent);
~TreeNode();
void appendChild(TreeNode *child);
void deleteAllChild();
TreeNode *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeNode *parent();
void setParent(TreeNode *parent);
void setNodeData(QVariant data, int index);
private:
TreeNode *pParentNode;
QList<TreeNode*> mChildNodes;
QList<QVariant> mNodeData;
};
TreeNode.cpp
#include "TreeNode.h"
TreeNode::TreeNode(const QList<QVariant> &data, TreeNode *parent)
{
pParentNode = parent;
mNodeData = data;
}
TreeNode::~TreeNode()
{
}
void TreeNode::appendChild(TreeNode *child)
{
child->setParent(this);
mChildNodes.append(child);
}
void TreeNode::deleteAllChild()
{
for (int index = 0; index < mChildNodes.size(); index++)
{
mChildNodes[index]->deleteAllChild();
}
qDeleteAll(mChildNodes);
mChildNodes.clear();
}
TreeNode *TreeNode::child(int row)
{
return mChildNodes.value(row);
}
int TreeNode::childCount() const
{
return mChildNodes.count();
}
int TreeNode::columnCount() const
{
return mNodeData.count();
}
QVariant TreeNode::data(int column) const
{
return mNodeData.value(column);
}
int TreeNode::row() const
{
return pParentNode == nullptr ? 0 : pParentNode->mChildNodes.indexOf(const_cast<TreeNode*>(this));
}
TreeNode *TreeNode::parent()
{
return pParentNode;
}
void TreeNode::setParent(TreeNode *parent)
{
pParentNode = parent;
}
void TreeNode::setNodeData(QVariant data, int index)
{
mNodeData[index] = data;
}
TreeModel.h
// TreeModel.h
#include <QAbstractItemModel>
#include <QObject>
#include "TreeNode.h"
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
enum nodeRoles {
NAME = Qt::UserRole + 1
};
public:
TreeModel(QObject *parent = nullptr);
~TreeModel();
void appendChild(const QModelIndex& index, QList<QVariant> dataList, int count);
void setNodeName(QString appendName, QModelIndex index);
int columnCount(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QHash<int, QByteArray> roleNames() const;
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
private:
TreeNode *pRootNode;
};
TreeModel.cpp
#include "TreeModel.h"
TreeModel::TreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> list;
list.append("RootNode");
pRootNode = new TreeNode(list, NULL);
QList<QVariant> list_zg;
list_zg.append(QString::fromLocal8Bit("中国"));
auto item_zg = new TreeNode(list_zg, pRootNode);
pRootNode->appendChild(item_zg);
QList<QVariant> list_sc;
list_sc.append(QString::fromLocal8Bit("四川"));
auto item_sc = new TreeNode(list_sc, item_zg);
item_zg->appendChild(item_sc);
}
TreeModel::~TreeModel()
{
pRootNode->deleteAllChild();
delete pRootNode;
}
void TreeModel::appendChild(const QModelIndex& index, QList<QVariant> dataList, int count)
{
TreeNode* clickNode = static_cast<TreeNode*>(index.internalPointer());
if (clickNode->childCount() && count == 0) { //刷新时先删除所有子节点
beginRemoveRows(index, 0, clickNode->childCount() - 1);
clickNode->deleteAllChild();
endRemoveRows();
}
TreeNode* pNode = new TreeNode(dataList, clickNode);
beginInsertRows(index, clickNode->childCount(), clickNode->childCount());
clickNode->appendChild(pNode);
endInsertRows();
}
void TreeModel::setNodeName(QString appendName, QModelIndex index)
{
TreeNode *pTreeNode = static_cast<TreeNode*>(index.internalPointer());
pTreeNode->setNodeData(appendName, 0);
emit dataChanged(index, index); //更新树节点数据
}
int TreeModel::columnCount(const QModelIndex &parent) const
{
return 1;
if (parent.isValid())
{
return static_cast<TreeNode*>(parent.internalPointer())->columnCount();
}
else
{
return pRootNode->columnCount();
}
}
int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeNode *parentNode;
if (parent.column() > 0)
{
return 0;
}
if (!parent.isValid())
{
parentNode = pRootNode;
}
else
{
parentNode = static_cast<TreeNode*>(parent.internalPointer());
}
return parentNode->childCount();
}
QHash<int, QByteArray> TreeModel::roleNames() const
{
QHash<int, QByteArray> names(QAbstractItemModel::roleNames());
names[NAME] = "name";
return names;
}
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
{
return QVariant();
}
switch (role)
{
case NAME:
{
return static_cast<TreeNode*>(index.internalPointer())->data(0);
}
}
return QVariant();
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
{
return 0;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
TreeNode *parentNode;
if (!parent.isValid())
{
parentNode = pRootNode;
}
else
{
parentNode = static_cast<TreeNode*>(parent.internalPointer());
}
TreeNode *childNode = parentNode->child(row);
if (childNode)
{
return createIndex(row, column, childNode);
}
else
{
return QModelIndex();
}
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
{
return QModelIndex();
}
TreeNode *childNode = static_cast<TreeNode*>(index.internalPointer());
TreeNode *parentNode = childNode->parent();
if (parentNode == pRootNode)
{
return QModelIndex();
}
return createIndex(parentNode->row(), 0, parentNode);
}
TreeViewController.h
#include <QObject>
#include "TreeModel.h"
class TreeViewController : public QObject
{
Q_OBJECT
public:
TreeViewController(QObject *parent = nullptr);
~TreeViewController();
public slots://被qml调用
Q_INVOKABLE QAbstractItemModel *getTreeModel();
Q_INVOKABLE void updateNodeName(const QModelIndex& index);
Q_INVOKABLE void updateNode(const QModelIndex& index);
private:
TreeModel* m_TreeModel;
};
TreeViewController.cpp
#include "TreeViewController.h"
TreeViewController::TreeViewController(QObject *parent)
: QObject(parent)
{
m_TreeModel = new TreeModel();
}
TreeViewController::~TreeViewController()
{
delete m_TreeModel;
}
QAbstractItemModel *TreeViewController::getTreeModel()
{
return m_TreeModel;
}
void TreeViewController::updateNodeName(const QModelIndex& index)
{
m_TreeModel->setNodeName("1", index);
}
void TreeViewController::updateNode(const QModelIndex& index)
{
QList<QVariant> list_sc;
list_sc.append(QString::fromLocal8Bit("四川"));
m_TreeModel->appendChild(index, list_sc, 0);
QList<QVariant> list_bj;
list_bj.append(QString::fromLocal8Bit("北京"));
m_TreeModel->appendChild(index, list_bj, 1);
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <qdebug.h>
#include "TreeViewController.h"
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
TreeViewController treeViewController; //理解析构顺序很重要
//qml 与 c++ 交互
engine.rootContext()->setContextProperty("mControl", &treeViewController);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4 //1.4版本才有TreeView
import QtQuick.Controls.Styles 1.4
import QtQml.Models 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("TreeView Test")
Rectangle {
id: root
height: parent.height
width: parent.width
color: "#87CEEB"
property var treeModel: mControl.getTreeModel()
//用于节点选中
ItemSelectionModel {
id: sel
model: root.treeModel
}
TreeView {
id: myTree
anchors.fill: parent
headerVisible: false
backgroundVisible : false //隐藏背景
style: treeViewStyle
model: root.treeModel
selection: sel
TableViewColumn {
width: myTree.width
title: "Name"
role: "name"
}
itemDelegate: Item {
Image {
id: nodeTextImage
anchors.verticalCenter: parent.verticalCenter
source: ""
}
Text {
id: nameText
anchors.left: nodeTextImage.right
anchors.leftMargin: 5
anchors.verticalCenter: parent.verticalCenter
color: "white"
elide: styleData.elideMode
text: styleData.value
font.pointSize: 16
}
Drag.active:itemMouse.drag.active
Drag.dragType: Drag.Automatic; //选择自动开始拖动
Drag.supportedActions: Qt.CopyAction; //选择复制数据到DropArea
Drag.onDragFinished: { //拖拽结束
}
MouseArea {
id: itemMouse
anchors.fill: parent
hoverEnabled: true
drag.target: nameText
property bool isExpand: true //点击展开树节点
onClicked: {
sel.setCurrentIndex(styleData.index, 0x0010) //点击Item,设置选中当前节点
if (isExpand) {
emit: myTree.expand(styleData.index)
isExpand = false;
mControl.updateNodeName(styleData.index)
}
else {
emit: myTree.collapse(styleData.index)
isExpand = true;
}
}
onDoubleClicked: { //刷新子节点
myTree.collapse(styleData.index) //先收起再展开,不然会有bug
mControl.updateNode(styleData.index)
myTree.expand(styleData.index)
}
}
}
}
}
Component {
id: treeViewStyle
TreeViewStyle {
padding.left: 2
padding.right: 2
indentation: 30 //节点间缩进
rowDelegate: Rectangle {
color: styleData.selected ? "#007DFF" : "transparent" //选中节点后的颜色和背景色
height: 30
}
/*
branchDelegate: Image { //节点展开收缩图标
id: nodeImage
source: {
return styleData.isExpanded ? "" : ""
}
}
*/
}
}
}
示例图:
双击节点更新节点,点击节点更新节点名