当前位置: 首页 > news >正文

Qt自定义TreeWidget,实现展开折叠按钮在右侧,且一条竖直线上对齐

效果如下:

图片随便找的,可能需要调下样式,代码复制可用,留给有需要的人。 

#ifndef CustomTreeWidget_h__
#define CustomTreeWidget_h__#include <QTreeWidget>
#include <QPushButton>class CCustomTreeWidget : public QTreeWidget
{Q_OBJECTpublic:CCustomTreeWidget(QWidget* parent = nullptr);~CCustomTreeWidget();QTreeWidgetItem* AddItem(QTreeWidgetItem* pParent = NULL);void ToggleItem(QTreeWidgetItem* pItem);void ExpandAllNodes();void CollapseAllNodes();protected:void mousePressEvent(QMouseEvent* event) override;void keyPressEvent(QKeyEvent* event) override;private:void UpdateItemWidget(QTreeWidgetItem* pItem);void UpdateAllButtons(const QIcon& icon);void UpdateItemButton(QTreeWidgetItem* pItem, const QIcon& icon);private slots:void SlotToggleNode(QTreeWidgetItem* pItem, QPushButton* pPushButton);};#endif // CustomTreeWidget_h__
#include "CustomTreeWidget.h"
#include <QHeaderView>
#include <QMouseEvent>
#include <QBoxLayout>CCustomTreeWidget::CCustomTreeWidget(QWidget* parent /*= nullptr*/): QTreeWidget(parent)
{setAttribute(Qt::WA_TranslucentBackground, true);setRootIsDecorated(false);setColumnCount(2);header()->hide();header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); // 第一列宽度自适应内容header()->setSectionResizeMode(1, QHeaderView::Fixed); // 第二列宽度固定setColumnWidth(1, 30); // 设置一个初始宽度,实际宽度会在按钮创建后更新// 隐藏默认的展开和折叠按钮setStyleSheet("QTreeView::branch:has-children:!has-siblings:closed,""QTreeView::branch:closed:has-children:has-siblings {""border-image: none; image: none;}""QTreeView::branch:open:has-children:!has-siblings,""QTreeView::branch:open:has-children:has-siblings {""border-image: none; image: none;}""QTreeWidget::item{ height: 20px; }");
}CCustomTreeWidget::~CCustomTreeWidget()
{}QTreeWidgetItem* CCustomTreeWidget::AddItem(QTreeWidgetItem* pParent)
{QTreeWidgetItem* pItem = NULL;if (NULL != pParent){pItem = new QTreeWidgetItem(pParent);pParent->addChild(pItem);UpdateItemWidget(pParent);}else{pItem = new QTreeWidgetItem();addTopLevelItem(pItem);UpdateItemWidget(pItem);}return pItem;
}void CCustomTreeWidget::ToggleItem(QTreeWidgetItem* pItem)
{if (NULL == pItem){return;}if (NULL != itemWidget(pItem, 1)){QPushButton* pPushButton = qobject_cast<QPushButton*>(itemWidget(pItem, 1)->findChild<QPushButton*>());if (pItem->isExpanded()){pPushButton->setIcon(QIcon(":/treeitem-expanded.png"));}else{pPushButton->setIcon(QIcon(":/treeitem-collapsed.png"));}}
}void CCustomTreeWidget::ExpandAllNodes()
{expandAll();UpdateAllButtons(QIcon(":/treeitem-expanded.png"));
}void CCustomTreeWidget::CollapseAllNodes()
{collapseAll();UpdateAllButtons(QIcon(":/treeitem-collapsed.png"));
}void CCustomTreeWidget::mousePressEvent(QMouseEvent* event)
{if (itemAt(event->pos())){event->accept();}else{QTreeWidget::mousePressEvent(event);}
}void CCustomTreeWidget::keyPressEvent(QKeyEvent* event)
{if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Left){event->ignore();}else{QTreeWidget::keyPressEvent(event);}
}void CCustomTreeWidget::UpdateItemWidget(QTreeWidgetItem* pItem)
{if (NULL == pItem){return;}if (pItem->childCount() > 0){QWidget* pWidget = new QWidget();QHBoxLayout* pLayout = new QHBoxLayout(pWidget);pLayout->setContentsMargins(0, 0, 0, 0);pLayout->setAlignment(Qt::AlignRight);QPushButton* pPushButton = new QPushButton();pPushButton->setStyleSheet("background: transparent; border: none;");QIcon icon(":/treeitem-collapsed.png");pPushButton->setIcon(icon);pPushButton->setIconSize(icon.availableSizes().first());pLayout->addWidget(pPushButton);pWidget->setLayout(pLayout);setItemWidget(pItem, 1, pWidget);const int nIconWidth = pPushButton->iconSize().width();setColumnWidth(1, nIconWidth);connect(pPushButton, &QPushButton::clicked, [this, pItem, pPushButton](){SlotToggleNode(pItem, pPushButton);});}else{if (QWidget* pWidget = itemWidget(pItem, 1)){delete pWidget;setItemWidget(pItem, 1, NULL);}}
}void CCustomTreeWidget::UpdateAllButtons(const QIcon& icon)
{for (int i = 0; i < topLevelItemCount(); ++i){UpdateItemButton(topLevelItem(i), icon);}
}void CCustomTreeWidget::UpdateItemButton(QTreeWidgetItem* pItem, const QIcon& icon)
{if (NULL != itemWidget(pItem, 1)){QPushButton* pPushButton = qobject_cast<QPushButton*>(itemWidget(pItem, 1)->findChild<QPushButton*>());if (NULL != pPushButton){pPushButton->setIcon(icon);}for (int i = 0; i < pItem->childCount(); ++i){UpdateItemButton(pItem->child(i), icon);}}
}void CCustomTreeWidget::SlotToggleNode(QTreeWidgetItem* pItem, QPushButton* pPushButton)
{if (pItem->isExpanded()){pItem->setExpanded(false);pPushButton->setIcon(QIcon(":/treeitem-collapsed.png"));}else{pItem->setExpanded(true);pPushButton->setIcon(QIcon(":/treeitem-expanded.png"));}
}

调用代码:

#include "CustomTreeWidget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);CCustomTreeWidget treeWidget;treeWidget.setWindowTitle("Custom Tree Widget");treeWidget.resize(400, 300);// 添加三个顶级节点QTreeWidgetItem* topLevelItem1 = treeWidget.AddItem();topLevelItem1->setText(0, "Top Level 1");QTreeWidgetItem* topLevelItem2 = treeWidget.AddItem();topLevelItem2->setText(0, "Top Level 2");QTreeWidgetItem* topLevelItem3 = treeWidget.AddItem();topLevelItem3->setText(0, "Top Level 3");// 为每个顶级节点增加三级子节点for (int i = 0; i < 3; ++i){QTreeWidgetItem* child1 = treeWidget.AddItem(topLevelItem1);child1->setText(0, QString("Child 1.%1").arg(i + 1));QTreeWidgetItem* child2 = treeWidget.AddItem(topLevelItem2);child2->setText(0, QString("Child 2.%1").arg(i + 1));QTreeWidgetItem* child3 = treeWidget.AddItem(topLevelItem3);child3->setText(0, QString("Child 3.%1").arg(i + 1));for (int j = 0; j < 3; ++j){QTreeWidgetItem* grandChild1 = treeWidget.AddItem(child1);grandChild1->setText(0, QString("Grandchild 1.%1.%2").arg(i + 1).arg(j + 1));QTreeWidgetItem* grandChild2 = treeWidget.AddItem(child2);grandChild2->setText(0, QString("Grandchild 2.%1.%2").arg(i + 1).arg(j + 1));QTreeWidgetItem* grandChild3 = treeWidget.AddItem(child3);grandChild3->setText(0, QString("Grandchild 3.%1.%2").arg(i + 1).arg(j + 1));}}treeWidget.show();return a.exec();
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 通过指令深入了解Linux 3
  • 基于深度学习的工业系统仿真
  • 网络安全测试工具Burp Suite基本使用
  • AWS Lambda 十年回顾:功能总览、更新记录与入门指南
  • 【微信小程序开发】——奶茶点餐小程序的制作(二)
  • OrangePi AIpro学习3 —— vscode开发昇腾DVPP程序
  • VMware-converter 4.0 5.0 6.2.0 版本 下载 P2V 物理机转虚拟机 实体机转虚拟机 V2V 虚拟机转虚拟机
  • Ubuntu 20.04 中安装 Nginx (通过传包编译的方式)、开启关闭防火墙、开放端口号
  • 浅谈【多线程与并发】之线程池
  • 2.如何定制 Dcat-admin list 中显示的信息
  • Java社会校招类型人力资源招聘系统小程序源码
  • Vue前端服务加密后端服务解密--AES算法实现
  • 数字信号处理3:数字滤波器设计
  • docker部署rabbitMQ
  • 用Python实现特征工程之特征变换——数值特征的归一化和标准化、类别特征的编码、特征组合和分解、特征缩放
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【347天】每日项目总结系列085(2018.01.18)
  • echarts花样作死的坑
  • FineReport中如何实现自动滚屏效果
  • pdf文件如何在线转换为jpg图片
  • Python_网络编程
  • ReactNative开发常用的三方模块
  • 阿里研究院入选中国企业智库系统影响力榜
  • 阿里云应用高可用服务公测发布
  • 彻底搞懂浏览器Event-loop
  • 对JS继承的一点思考
  • 看域名解析域名安全对SEO的影响
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 前言-如何学习区块链
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 用mpvue开发微信小程序
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • ​Java并发新构件之Exchanger
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (不用互三)AI绘画工具应该如何选择
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (三分钟)速览传统边缘检测算子
  • (十)Flink Table API 和 SQL 基本概念
  • (十八)三元表达式和列表解析
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET MVC第三章、三种传值方式
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .Net程序帮助文档制作
  • /var/spool/postfix/maildrop 下有大量文件
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • ??eclipse的安装配置问题!??
  • [].slice.call()将类数组转化为真正的数组
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——