QML TreeView使用例子

2 篇文章 0 订阅

记录 QML TreeView 使用

参考链接:

QML树控件TreeView的使用(上)

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 ? "" : ""
                }
            }
*/
        }
    }
}

示例图:

 双击节点更新节点,点击节点更新节点名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值