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

news2024/11/15 17:30:02

效果如下:

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

#ifndef CustomTreeWidget_h__
#define CustomTreeWidget_h__

#include <QTreeWidget>
#include <QPushButton>

class CCustomTreeWidget : public QTreeWidget
{
	Q_OBJECT

public:
	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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CTF | WEB】001、攻防世界WEB题目之backup

文章目录 backup题目描述:解题思路&#xff1a;解题过程&#xff1a; backup 题目描述: X老师忘记删除备份文件&#xff0c;他派小宁同学去把备份文件找出来,一起来帮小宁同学吧&#xff01; 进入题目后显示&#xff1a; 解题思路&#xff1a; 在进行网站安全检查时&#xf…

北大和鹏城实验室联合推出的图像视频统一多模态大模型Chat-UniVi(CVPR 2024)

Chat-UniVi: Unified Visual Representation Empowers Large Language Models with Image and Video Understanding 论文信息 paper&#xff1a;CVPR 2024 code&#xff1a;https://github.com/PKU-YuanGroup/Chat-UniVi 训练130亿大模型仅3天&#xff0c;北大提出Chat-UniVi…

实战|uniapp模仿微信实现发送位置消息,解决滚动页面地图层级冲突

前言 在即时通讯应用中&#xff0c;虽然发送位置信息不是核心功能&#xff0c;但在特定场景下&#xff0c;这个功能仍然非常有用。 本文将介绍如何在 uniapp 中实现位置信息的发送和展示&#xff0c;特别是在遇到地图层级问题时的解决方案。 以下内容均基于 uniapp 打包 App …

puppeteersharp爬取网页数据

官网 https://github.com/hardkoded/puppeteer-sharp 安装 创建控制台项目&#xff0c;安装PuppeteerSharp 18.1.0 编写代码 安装chrome async static Task Main(string[] args) {//如果Chromium不存在则先下载var browserFetcher new BrowserFetcher();//获取安装的浏览…

redis面试(十三)公平锁排队代码剖析

我们来看一下第二种redis分布式锁 第一种锁是可重入锁&#xff0c;非公平可重入锁&#xff0c;所谓的非公平可重入锁是什么意思呢&#xff1f;胡乱的争抢&#xff0c;根本没有任何公平性和顺序性可言 第二种锁&#xff0c;可重入锁&#xff0c;公平锁 通过公平锁&#xff0c…

haproxy七层代理总结

一、HAProxy概念 1.1 什么是HAProxy&#xff1f; HAProxy是一款开源、高性能的负载均衡器和代理服务器&#xff0c;专为TCP和HTTP应用而设计。它可以将客户端的请求分发到多台后端服务器&#xff0c;从而提高应用的可用性和性能。HAProxy支持多种负载均衡算法和健康检查机制&a…

一篇文章带你学会向量数据库Milvus

一篇文章带你学会向量数据库Milvus 索引管理 Milvus 提供多种索引类型来对字段值进行排序&#xff0c;以实现高效的相似性搜索。它还提供三种度量类型&#xff1a;余弦相似度 (COSINE)、欧几里得距离 (L2) 和内积 &#xff08;IP&#xff09;来测量向量嵌入之间的距离。 建议…

零基础学会机器学习,到底要多久?

这两天啊&#xff0c;有不少朋友和我说&#xff0c;想学机器学习&#xff0c;但是之前没有基础&#xff0c;不知道能不能学得会。 首先说结论&#xff0c;只要坚持&#xff0c;就能学会&#xff0c;但是一定不能三天打鱼两天晒网&#xff0c;要持之以恒&#xff0c;至少每隔两…

小白零基础学数学建模系列-Day4-线性规划基础与案例分析

文章目录 1. 线性规划基础1.1 基本概念1.2 求解方法 2 线性规划经典问题2.1 生产计划问题2. 2 运输问题 案例1&#xff1a;生产计划问题背景模型建立模型求解 案例2&#xff1a;运输问题背景模型建立模型求解 案例3&#xff1a;货机货物装载问题问题背景假设条件问题要求模型建…

【微信小程序】WXSS 模板样式

1. 什么是 WXSS WXSS (WeiXin Style Sheets)是一套样式语言,用于美化 WXML 的组件样式,类似于网页开发中的 CSS。 2. WXSS 和 CSS 的关系 3.rpx (1). 什么是 rpx 尺寸单位 rpx(responsive pixel)是微信小程序独有的,用来解决屏适配的尺寸单位。 (2). rpx 的实现原理 …

哈希表 -四数相加II

454. 四数相加II 方法一&#xff1a;分组哈希表 /*** param {number[]} nums1* param {number[]} nums2* param {number[]} nums3* param {number[]} nums4* return {number}*/ var fourSumCount function(nums1, nums2, nums3, nums4) {const twoSumMap new Map();let coun…

【机器学习之深度学习】深度学习和机器学习的关系以及深度学习的应用场景

引言 深度学习和机器学习是人工智能领域的两个重要分支&#xff0c;它们之间既有联系也有区别 文章目录 引言一、深度学习和机器学习的关系1.1 联系1.2 区别1.2.1 模型复杂度1.2.2 数据需求1.2.3 特征提取1.2.4 训练速度和计算资源 二、深度学习有哪些应用场景2.1 计算机视觉2.…

Unity | AmplifyShaderEditor插件基础(第一集:简单了解ASE和初识)

前言 我本来老老实实的写着我的Shader&#xff0c;群里的小伙伴强烈建议我开始讲ASE&#xff0c;我只能说&#xff0c;我是一个听话的Up。 一、什么是ASE 全称AmplifyShaderEditor&#xff0c;是一个unity插件&#xff0c;存在于unity商城中&#xff0c;售价看他们心情。&am…

deepin V23 前瞻丨深度适配RISC-V架构,打造全面兼容与高性能的开源桌面操作系统

查看原文 中国工程院院士倪光南曾表示&#xff0c;RISC-V架构因其开放性和灵活性&#xff0c;已成为中国CPU领域最受欢迎的选择之一&#xff0c;并有望成为推动新一代信息技术发展的关键驱动力。目前&#xff0c;deepin&#xff08;深度&#xff09;社区已与RISC-V生态系统建立…

ECMAScript6语法:类

在 ES6 中新增了类的概率&#xff0c;多个具有相同属性和方法的对象就可以抽象为类。类和对象的关系如下&#xff1a; &#xff08;1&#xff09;类抽象了对象的公共部分&#xff0c;它泛指某一大类&#xff08;class&#xff09;。 &#xff08;2&#xff09;对象特指通过类…

haproxy 7000字配图超详细教程 从小白到入门

简介&#xff1a;HAProxy是一个免费的负载均衡软件&#xff0c;可以运行于大部分主流的Linux操作系统上。HAProxy提供了L4(TCP)和L7(HTTP)两种负载均衡能力&#xff0c;具备丰富的功能。HAProxy的社区非常活跃&#xff0c;版本更新快速,HAProxy具备媲美商用负载均衡器的性能和稳…

基于python理解最大似然MLE-(简单正态分布估计、高斯混合模型GMM)

最大似然法&#xff08;Maximum Likelihood Estimation&#xff0c;简称MLE&#xff09;是一种统计方法&#xff0c;用于估计概率模型的参数。其基本思想是寻找一组参数值&#xff0c;使得在这组参数下&#xff0c;观测数据出现的概率&#xff08;即似然性&#xff09;最大。这…

ARM64 在线仿真器

今天在晚上找到一个简单的ARM64在线仿真器&#xff0c;它非常适合学习ARM64的指令&#xff0c;在教学中应该很好用。网址ARM64 Online Simulatorhttp://163.238.35.161/~zhangs/arm64simulator/ 它是由康涅狄格州立大学的Shuqun Zhang教授开发的。软件基于Alexandro Sanchez开…

评价算法(topsis熵权法)

评价算法 熵权法 上面箭头的一步用到了带权重的距离公式。 上面是某种求权重的方法&#xff0c;合理就行。 但是在使用熵权法的时候&#xff0c;一定要注意用的是规范化矩阵再用熵权法求权重。 规范化之前一定要判断每一列的性质 #熵权法&#xff1a;import xlrd import num…

巴黎奥运会背后的8K国际公用信号制作

北京时间2024年8月12日凌晨3时&#xff0c;举世瞩目的巴黎奥运会闭幕式在法兰西体育场举行&#xff0c;闭幕式演出部分的主题为“记录”。BOSMA博冠首款8K 50P小型化广播级摄像机B1跟随中央广播电视总台“中国红”8K转播车&#xff0c;为田径比赛和闭幕式提供8K国际公用信号制作…