因为项目需要,最近在学习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
}
}