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
	}
}

猜你喜欢

转载自blog.csdn.net/qq_45523399/article/details/116102884
QML