QML TreeView的简单自定义样式

因为项目需要,最近在学习QML,用到了TreeView组件,网上没找到符合需求的合适的样式,就自己调整了一下,在此做个记录。

import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQml.Models 2.15

Rectangle{
    id:root
    width: 300
    height: 500
    color: "#d2d2d2"

    TreeView{
        id:tree
        //visible: false
        anchors.fill: parent
        anchors.topMargin: 10
        anchors.bottomMargin: 10
        anchors.leftMargin: 10
        anchors.rightMargin: 10
        TableViewColumn{
            title:"name"
            role:"name"
            width: tree.width
        }
        model:EquipTreeView
        style: treeViewStyle
        selection: sel
        frameVisible: false//隐藏边框
        backgroundVisible: false
        sortIndicatorVisible: true//这句不太清楚什么含义
        headerVisible: false
        itemDelegate: Item{
            id:treeItem
            Rectangle{
                id:itemRect
                anchors.fill:parent
                //通过设置项圆角矩形相对于项高的上下边距来实现项间间隔效果
                //如果仅设置单边边距会导致圆角矩形向上或向下偏移,与文字不垂直居中,还需再进行定位,很麻烦
                //上下边距设为希望的项间隔的1/2,项高设为原项高+上下边距的高度
                anchors.topMargin: 1.5
                anchors.bottomMargin: 1.5
                width: tree.width
                radius:5
                color:styleData.selected?"#8abcdb":getColor(styleData.index)
            }
            Text{
                id:itemText
                anchors.fill: parent
                anchors.leftMargin: 4
                text:styleData.value
                font.family:"微软雅黑"
                color: "#ffffff"//styleData.selected?"#3742db":"#ffffff"//选中时文字颜色切换
                font.pointSize: 11//styleData.selected?12:11//选中时文字大小切换
                verticalAlignment: Text.AlignVCenter
                MouseArea{
                    id:itemMouse
                    hoverEnabled: true
                    anchors.fill:parent
                    drag.target: itemText//这句不太清楚什么含义,不过注掉之后,如果鼠标按下和释放不在同一点上会触发选中
                    onPressed: {

                    }
                    onReleased: {

                    }
                    onClicked: {
                        sel.setCurrentIndex(styleData.index,0x0010)//点击文本,选中该节点
                    }
                    onDoubleClicked: {
                        if(styleData.isExpanded)//切换节点的展开状态
                        {
                            tree.collapse(styleData.index)
                        }
                        else
                        {
                            tree.expand(styleData.index)
                        }
                    }
                }
            }
        }
        ItemSelectionModel//添加自定义选中
        {
            id:sel
            model:EquipTreeView
        }
        Component{
            id:treeViewStyle
            TreeViewStyle//树的自定义样式
            {
                indentation: 20//节点首缩进
                backgroundColor: "transparent"//背景透明
                branchDelegate: Image{//节点展开标记图
                    id:image
                    source: styleData.isExpanded?"./down.png":"./right.png"//项前的三角图标
                    width:15
                    height: 15
                }
                rowDelegate:Rectangle{
                    id:rowRec
                    height:33//项高
                    color:"transparent"//背景透明
                }
            }
        }
        onClicked: {

        }
    }

    Rectangle{
        x: 0
        y: 400
        width: root.width
        height: 100
        color:"#6e6e6e"
        Rectangle{
            x: 33
            y: 20
            width: 10
            height: 10
            color:"#4a8fba"
        }
        Text{
            x: 55
            y: 14
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"国家"
        }
        Rectangle{
            x: 117
            y: 20
            width: 10
            height: 10
            color:"#f0af72"
        }
        Text{
            x: 140
            y: 14
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"省份"
        }
        Rectangle{
            x: 200
            y: 20
            width: 10
            height: 10
            color:"#d48484"
        }
        Text{
            x: 224
            y: 14
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"直辖市"
        }
        Rectangle{
            x: 33
            y: 45
            width: 10
            height: 10
            color:"#92d791"
        }
        Text{
            x: 55
            y: 40
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"城市"
        }
        Rectangle{
            x: 117
            y: 45
            width: 10
            height: 10
            color:"#de8ad5"
        }
        Text{
            x: 148
            y: 40
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"区"
        }
        Rectangle{
            x: 200
            y: 45
            width: 10
            height: 10
            color:"#bbbbbb"
        }
        Text{
            x: 232
            y: 40
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"未知"
        }
        Rectangle{
            x: 33
            y: 73
            width: 10
            height: 10
            color:"#8abcdb"
        }
        Text{
            x: 55
            y: 66
            font.family:"微软雅黑"
            color:"#ffffff"
            text:"选中"
        }
    }

    //根据每一项的类型返回不同的颜色
    function getColor(index){
        var type = EquipTreeView.getType(index)
        if(type == "Country")
        {
            return "#4a8fba"
        }
        else if(type == "Province")
        {
            return "#f0af72"
        }
        else if(type == "Municipality")
        {
            return "#d48484"
        }
        else if(type == "City")
        {
            return "#92d791"
        }
        else if(type == "District")
        {
            return "#de8ad5"
        }
        else
        {
            return "#bbbbbb"
        }
    }
}

运行效果:

界面效果
model的写法参考以下文章:
https://blog.csdn.net/Shado_walker/article/details/56495059

做了如下修改:

enum ItemRoles {
	NAME = Qt::UserRole + 1,
	TYPE
};
m_rootItem = new TreeItem;
QList<QVariant> list;
list.append("ZhongGuo");
list.append("Country");
auto item = new TreeItem(list, m_rootItem);
m_rootItem->appendChild(item);

QList<QVariant> BJ_List;
BJ_List.append("BeiJing");
BJ_List.append("Municipality");
auto BJ_Item = new TreeItem(BJ_List, item);
item->appendChild(BJ_Item);

QList<QVariant> SH_List;
SH_List.append("ShangHai");
SH_List.append("Municipality");
auto SH_Item = new TreeItem(SH_List, item);
item->appendChild(SH_Item);

QList<QVariant> HP_List;
HP_List.append("HuangPu");
HP_List.append("District");
auto HP_Item = new TreeItem(HP_List, SH_Item);
SH_Item->appendChild(HP_Item);

QList<QVariant> GD_List;
GD_List.append("GuangDong");
GD_List.append("Province");
auto GD_Item = new TreeItem(GD_List, item);
item->appendChild(GD_Item);

QList<QVariant> GZ_List;
GZ_List.append("GuangZhou");
GZ_List.append("City");
auto GZ_Item = new TreeItem(GZ_List, GD_Item);
GD_Item->appendChild(GZ_Item);

QList<QVariant> TH_List;
TH_List.append("TianHe");
TH_List.append("District");
auto TH_Item = new TreeItem(TH_List, GZ_Item);
GZ_Item->appendChild(TH_Item);

QList<QVariant> ZH_List;
ZH_List.append("ZhuHai");
ZH_List.append("City");
auto ZH_Item = new TreeItem(ZH_List, GD_Item);
GD_Item->appendChild(ZH_Item);

QList<QVariant> XZ_List;
XZ_List.append("XiangZhou");
XZ_List.append("District");
auto XZ_Item = new TreeItem(XZ_List, ZH_Item);
ZH_Item->appendChild(XZ_Item);

QList<QVariant> ZJ_List;
ZJ_List.append("ZheJiang");
ZJ_List.append("Province");
auto ZJ_Item = new TreeItem(ZJ_List, item);
item->appendChild(ZJ_Item);

QList<QVariant> HZ_List;
HZ_List.append("HangZhou");
HZ_List.append("City");
auto HZ_Item = new TreeItem(HZ_List, ZJ_Item);
ZJ_Item->appendChild(HZ_Item);

QList<QVariant> GS_List;
GS_List.append("GongShu");
GS_List.append("District");
auto GS_Item = new TreeItem(GS_List, HZ_Item);
HZ_Item->appendChild(GS_Item);
QHash<int, QByteArray> CusTreeModel::roleNames() const
{
	QHash<int, QByteArray> names(QAbstractItemModel::roleNames());
	names[NAME] = "name";
	names[TYPE] = "type";
	return names;
}
QVariant CusTreeModel::data(const QModelIndex& index, int role) const
{
	if (!index.isValid())
	{
		return QVariant();
	}

	switch (role)
	{
	case NAME:
	{
		return static_cast<TreeItem*>(index.internalPointer())->data(0);
	}
	case TYPE:
	{
		return static_cast<TreeItem*>(index.internalPointer())->data(1);
	}
	}
}

新增函数:

//函数声明:Q_INVOKABLE QString getType(const QModelIndex& index);
//注意:需要Q_INVOKABLE宏进行修饰才能在QML中调用
QString CusTreeModel::getType(const QModelIndex& index)
{
	if (!index.isValid())
	{
		return "";
	}

	TreeItem* item = static_cast<TreeItem*>(index.internalPointer());

	return item->data(1).toString();
}

如果需要使用自定义滚动条:

verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff//将TreeView的自带ScrollBar隐藏掉
ScrollBar{
	id:vBar
	hoverEnabled: true
	active: hovered||pressed
	orientation: Qt.Vertical
	size:tree.height/tree.flickableItem.contentHeight
	anchors.top: parent.top
 	anchors.right: parent.right
 	anchors.bottom: parent.bottom
	onPositionChanged: {//拖动ScrollBar时,滚动TreeView
	tree.flickableItem.contentY = position*(tree.flickableItem.contentHeight)
	}
}
Connections{
	target: tree.flickableItem
	onContentYChanged:{//鼠标滚动TreeView时,同步ScrollBar位置
	vBar.position = tree.flickableItem.contentY/tree.flickableItem.contentHeight
	}
}
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
QML 中使用 TreeView 显示树形结构时,需要使用自定义模型。下面是一个简单的例子: 首先,我们需要创建一个继承自 QAbstractItemModel 的自定义模型类,这个类需要实现以下方法: ```cpp int rowCount(const QModelIndex &parent = QModelIndex()) const; // 返回指定父节点下的子节点数目 int columnCount(const QModelIndex &parent = QModelIndex()) const; // 返回每个节点的列数 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; // 返回指定节点的指定角色数据 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; // 返回指定行列下的索引 QModelIndex parent(const QModelIndex &index) const; // 返回指定节点的父节点索引 ``` 下面是一个示例模型类的实现: ```cpp class MyTreeModel : public QAbstractItemModel { Q_OBJECT public: explicit MyTreeModel(QObject *parent = nullptr); // 重写 QAbstractItemModel 的方法 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; private: QList<QStringList> m_data; // 存储树形数据 }; ``` 在构造函数中初始化数据: ```cpp MyTreeModel::MyTreeModel(QObject *parent) : QAbstractItemModel(parent) { QStringList rootData; rootData << "Name" << "Description"; m_data.append(rootData); QStringList childData; childData << "John" << "A guy"; rootData.append(childData); m_data.append(rootData); childData.clear(); childData << "Bill" << "Another guy"; rootData.clear(); rootData << "Another" << "Description"; rootData.append(childData); m_data.append(rootData); } ``` 接下来,实现重写的 QAbstractItemModel 方法: ```cpp QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); if (!parent.isValid()) return createIndex(row, column, 0); auto parentData = m_data[parent.row()]; if (row < parentData.size()) return createIndex(row, column, &parentData[row]); else return QModelIndex(); } QModelIndex MyTreeModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); QString parentData = *static_cast<QString*>(child.internalPointer()); for (int i = 0; i < m_data.size(); ++i) { auto rowData = m_data[i]; for (int j = 0; j < rowData.size(); ++j) { if (rowData[j] == parentData) { return createIndex(i, 0, &m_data[i][0]); } } } return QModelIndex(); } int MyTreeModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; if (!parent.isValid()) return m_data.size(); auto parentData = m_data[parent.row()]; return parentData.size(); } int MyTreeModel::columnCount(const QModelIndex &parent) const { return 2; } QVariant MyTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); auto data = m_data[index.row()][index.column()]; return QVariant::fromValue(data); } ``` 最后,在 QML 中使用 TreeView 组件,并使用自定义模型: ```qml import QtQuick.Controls 2.15 TreeView { model: MyTreeModel {} TableViewColumn { role: "Name" title: "Name" width: 100 } TableViewColumn { role: "Description" title: "Description" width: 200 } } ``` 这样就完成了使用自定义模型在 QML 中显示树形结构的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值