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

18 篇文章 1 订阅
12 篇文章 0 订阅

效果如下:

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

#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();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中,可以使用QTreeWidget来创建树形结构。要实现展开一个节点时收缩上一个节点,可以使用QTreeWidget的信号和槽机制。 首先,需要连接QTreeWidget的itemExpanded()信号和itemCollapsed()信号到槽函数中。这些信号分别在节点展开和收缩时触发。 在槽函数中,可以使用QTreeWidgetItemIterator遍历所有节点,然后判断哪些节点需要收缩。对于需要收缩的节点,可以使用QTreeWidget的collapseItem()函数来收缩节点。 下面是一个示例代码,展示如何在展开一个节点时收缩上一个节点: ```cpp void MyTreeWidget::onItemExpanded(QTreeWidgetItem* item) { // Traverse all items in the tree QTreeWidgetItemIterator it(this); while (*it) { // Check if the item is not the expanded item and is expanded if (*it != item && (*it)->isExpanded()) { // Collapse the item collapseItem(*it); } ++it; } } void MyTreeWidget::onItemCollapsed(QTreeWidgetItem* item) { // Do nothing } ``` 在上面的代码中,onItemExpanded()槽函数会在一个节点被展开时被调用。它会遍历所有节点,如果遇到一个节点不是被展开的节点且它是展开的状态,那么就会收缩它。onItemCollapsed()槽函数会在一个节点被收缩时被调用,但是它不需要做任何事情。 最后,需要在构造函数中连接itemExpanded()信号和itemCollapsed()信号到对应的槽函数: ```cpp MyTreeWidget::MyTreeWidget(QWidget* parent) : QTreeWidget(parent) { // Connect signals and slots connect(this, &QTreeWidget::itemExpanded, this, &MyTreeWidget::onItemExpanded); connect(this, &QTreeWidget::itemCollapsed, this, &MyTreeWidget::onItemCollapsed); } ``` 这样,当用户展开一个节点时,它会自动收缩上一个节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值