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();
}
相关文章:
Qt自定义TreeWidget,实现展开折叠按钮在右侧,且一条竖直线上对齐
效果如下: 图片随便找的,可能需要调下样式,代码复制可用,留给有需要的人。 #ifndef CustomTreeWidget_h__ #define CustomTreeWidget_h__#include <QTreeWidget> #include <QPushButton>class CCustomTreeWidget : p…...
硅步千里:如何入行?——之入行成为软件开发者
无论何时,你是否有遇到这样的场景(在自己从未涉足过的行业或领域,现在需要自己去这个行业或领域学习探索,最初的目标是熟悉行业,快速融入进去,很多时候,我们只是了解了个大概,并没能…...
Sandbox: rsync.samba(80134) deny(1) file-write-create
Xcode15运行报错:Sandbox: rsync.samba(80134) deny(1) file-write-create/xxx/xxx 如下图: 解决办法: Build Settings 搜索 sandbox,把 Build Options 中的 User Script Sandboxing改为 NO...
lvs的dr模式综合实践
目录 编辑虚拟机准备工作 编辑编辑编辑 配置过程 配置client主机 配置router主机 配置lvs主机(vip使用环回来创建) 配置server1主机(vip使用环回来创建) 配置server2主机(vip使用环回来创建࿰…...
什么是自然语言处理
自然语言处理(Natural Language Processing, NLP)是人工智能(AI)的一个子领域,涉及计算机与人类语言的交互。它的目标是让计算机能够理解、分析、生成和操作自然语言,从而实现与人类的有效沟通。 自然语言处…...
快速理解互联网中的常用名词
并发与并行 并发:任务交替执行,伪并行,涉及CPU时间片和上下文切换。并行:任务真正同时执行,需要多核处理器,无上下文切换。 并发量(Concurrency) 概念:服务端程序单位…...
统计接口调用耗时_黑白名单配置
黑名单配置 黑名单就是那些被禁止访问的URL创建自定义过滤器 BlackListUrlFilter,并配置黑名单地址列表blacklistUrl如果有其他需求,还可以实现自定义规则的过滤器来满足特定的过滤要求 /*** 黑名单过滤器** author canghe*/ Component public class B…...
树莓派4 AV没有视频输出
使用AV接口输出,没有画面 需要在config.txt文件中 增加配置 enable_tvout1config.txt 中的 dtoverlayvc4-kms-v3d 行末尾添加,composite: dtoverlayvc4-kms-v3d,composite默认情况下,输出 NTSC 复合视频。要选择不同的模式,请在…...
短信群发平台:解决短信验证码接收问题的5大策略
在享受数字化服务时,如APP注册或网站登录,若遇到短信验证码无法接收的困扰,无疑会增添不少烦恼。为了帮助您迅速解决这一问题,我们精心总结了以下十大原因及对应的解决方法,助您顺畅完成验证流程。 一、优化网络环境 …...
WebSocket 初体验:构建实时通信应用
WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行双向通信,从而实现低延迟的数据交换。WebSocket非常适合需要实时交互的应用场景,比如聊天应用、在线游戏、实时数据分析等。 WebSocket简介 什么是WebSocket…...
LISA: Reasoning Segmentation via Large Language Model
发表时间:CVPR 2024 论文链接:https://openaccess.thecvf.com/content/CVPR2024/papers/Lai_LISA_Reasoning_Segmentation_via_Large_Language_Model_CVPR_2024_paper.pdf 作者单位:CUHK Motivation:尽管感知系统近年来取得了显…...
企业发展与数字化转型:创新驱动未来增长的关键策略
引言 在当今全球化和信息化高度融合的时代,数字化转型已经成为企业寻求增长和保持竞争优势的关键战略。随着技术的飞速进步,数字化不仅改变了商业模式和市场格局,还深刻影响了企业的内部运作和外部生态系统。大数据、人工智能、物联网等新兴技…...
如何选择适合自己的编程语言,为什么R是非计算机专业数据分析的最佳选择,五大点告诉你
在如今的数据驱动世界中,编程语言已成为希望在行业中进行数据分析的专业人士不可或缺的技能。对于非计算机专业背景的学者和学生来说,选择适合自己的编程语言可能看似困难。本文将探讨为什么对于那些需要进行本科生论文、研究生论文、或者发表学术成果的…...
【经验分享】数据结构——求树的叶子结点个数计算方法
目录 一道题就可以学会 这种题做法固定,记住两个公式即可 解惑: 1、为什么n2010110x? 2、为什么是n-120*410*31*210*1x*0? 🌈 嗨,我是命运之光! 🌌 2024,每日百字&…...
第十一章:图论part04 110.字符串接龙 105.有向图的完全可达性 106.岛屿的周长(补)
任务日期:7.29 题目一链接:110. 字符串接龙 (kamacoder.com) 思路:将本题寻找附近的字符串等效于寻找四周的陆地,即寻找周围与当前字符只有一位不同的字符串,然后加入到队列中并标记上,在此基础上要将字符…...
Linux中安装MYSQL数据库
文章目录 一、MYSQL数据库介绍1.1、MySQL数据库的基本概述1.2、MySQL数据库的主要特性1.3、MySQL数据库的技术架构与组件1.4、MySQL数据库的应用与扩展性1.5、MySQL数据库的许可模式与开源生态 二、MySQL Workbench和phpMyAdmin介绍2.1、MySQL Workbench介绍2.2、phpMyAdmin介绍…...
Vue前端服务加密后端服务解密--AES算法实现
在实际项目中考虑到用户数据的安全性,在用户登录时,前端需要对用户密码加密(防止用户密码泄露),服务端收到登录请求时先对密码进行解密,然后再进行用户验证登操作。本文使用 AES ECB 模式算法来实现前端机密…...
matlab实现文字识别
在MATLAB中实现文字识别通常涉及图像处理技术和机器学习算法,特别是使用MATLAB内置的Image Processing Toolbox和Machine Learning Toolbox。下面是一个基本的步骤指南,展示如何在MATLAB中设置和执行一个简单的OCR(Optical Character Recogni…...
Leetcode - 周赛409
目录 一,3242. 设计相邻元素求和服务 二,3243. 新增道路查询后的最短距离 I 三,3244. 新增道路查询后的最短距离 II 四,3245. 交替组 III 一,3242. 设计相邻元素求和服务 本题纯模拟,代码如下ÿ…...
突破百度网盘的下载限速,两种方法教会你【超详细】
一、前言 Hello,大家后,我是博主英杰,前几天,我在使用百度网盘过程中,下载速度极慢,自己作为一个白嫖党,开会员也是心疼那点钱,所以在网上找了几个有效解决百度网盘限速问题的教程&a…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
