Qt界面篇:Qt停靠控件QDockWidget、树控件QTreeWidget及属性控件QtTreePropertyBrowser的使用

本文介绍了如何使用Qt的QDockWidget停靠控件、QTreeWidget树控件以及QtTreePropertyBrowser属性控件来创建主界面布局。内容包括QDockWidget的停靠功能,QTreeWidget的基本使用和实现连接线的方法,以及QtTreePropertyBrowser的介绍和使用中遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、功能介绍

  本篇主要使用Qt停靠控件QDockWidget、树控件QTreeWidget及Qt属性控件QtTreePropertyBrowser来搭建一个简单实用的主界面布局。效果如下所示。
在这里插入图片描述

2、控件使用详解

2.1 停靠控件QDockWidget

  QDockWidget可以停靠在 QMainWindow 内或作为桌面上的顶级窗口浮动。默认值为 Qt::AllDockWidgetAreas。下面是停靠区域的枚举值。

Qt::LeftDockWidgetArea
Qt::RightDockWidgetArea
Qt::TopDockWidgetArea
Qt::BottomDockWidgetArea
Qt::AllDockWidgetAreas
Qt::NoDockWidgetArea

  QDockWidget可以直接从Qt designer的部件列表中拖拽即可,或者用纯代码进行添加和布局,这两种方式都可以。此处采用的是拖拽的方式进行的添加。然后依据需要在dock控件内嵌入了树控件和属性控件。
在这里插入图片描述

2.2 树控件QTreeWidget

  QTreeWidget是由Qt提供的树形表达控件,默认已经进行了一些封装,便于快速使用。如果想更高度化自由定制的话可以采用Tree view控件。需要注意的是
setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
设定好Qt::ItemIsAutoTristate属性后,父级子级的勾选复选框会自动进行变化,比较方便。

在这里插入图片描述

2.2.1 初步使用

下面是QTreeWidget的简单用法:

在这里插入图片描述

void QVisualSystem::InitialBrowserTree()
{
	// 添加节点间连接线但会导致Qt::ItemIsAutoTristate失效
	//ui.BrowserTree->setStyle(QStyleFactory::create("windows"));
	ui.BrowserTree->setIconSize(QSize(32, 32));
	ui.BrowserTree->setColumnCount(1);
	ui.BrowserTree->setColumnWidth(0, 300);

	QString sQssStyle = getQssStyle();
	ui.BrowserTree->setStyleSheet(sQssStyle);

	ui.BrowserTree->setHeaderHidden(true);  //隐藏表头

	//第一个分组
	QTreeWidgetItem* group1 = new QTreeWidgetItem(ui.BrowserTree);
	group1->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
	group1->setText(0, QString::fromStdWString(L"专业"));

	QTreeWidgetItem* subItem1 = new QTreeWidgetItem(group1);
	subItem1->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
	subItem1->setText(0, QString::fromStdWString(L"热力"));
	subItem1->setCheckState(0, Qt::Unchecked);
	{
		QTreeWidgetItem* subItem11 = new QTreeWidgetItem(subItem1);
		subItem11->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem11->setText(0, QString::fromStdWString(L"供暖"));
		subItem11->setCheckState(0, Qt::Unchecked);

		QTreeWidgetItem* subItem12 = new QTreeWidgetItem(subItem1);
		subItem12->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem12->setText(0, QString::fromStdWString(L"地热"));
		subItem12->setCheckState(0, Qt::Unchecked);
	}
	
	QTreeWidgetItem* subItem2 = new QTreeWidgetItem(group1);
	subItem2->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
	subItem2->setText(0, QString::fromStdWString(L"给水"));
	subItem2->setCheckState(0, Qt::Unchecked);
	{
		QTreeWidgetItem* subItem11 = new QTreeWidgetItem(subItem2);
		subItem11->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem11->setText(0, QString::fromStdWString(L"家用水"));
		subItem11->setCheckState(0, Qt::Unchecked);

		QTreeWidgetItem* subItem12 = new QTreeWidgetItem(subItem2);
		subItem12->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem12->setText(0, QString::fromStdWString(L"工业水"));
		subItem12->setCheckState(0, Qt::Unchecked);
	}

	QTreeWidgetItem* subItem3 = new QTreeWidgetItem(group1);
	subItem3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
	subItem3->setText(0, QString::fromStdWString(L"雨污"));
	subItem3->setCheckState(0, Qt::Unchecked);
	{
		QTreeWidgetItem* subItem11 = new QTreeWidgetItem(subItem3);
		subItem11->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem11->setText(0, QString::fromStdWString(L"雨水"));
		subItem11->setCheckState(0, Qt::Unchecked);

		QTreeWidgetItem* subItem12 = new QTreeWidgetItem(subItem3);
		subItem12->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate);
		subItem12->setText(0, QString::fromStdWString(L"污水"));
		subItem12->setCheckState(0, Qt::Unchecked);
	}

	ui.BrowserTree->expandAll();
}

2.2.2 实现连接线

  假如我们想要使QTreeWidget实现类似于windows的叶子结点之间连线的效果,有两种实现方式,一种是直接代码处理,另外一种是使用QSS样式设置,个人推荐使用QSS,毕竟比较灵活且便于修改维护。

  下面是直接写代码处理,但会导致Qt::ItemIsAutoTristate复选框勾选失效。

// 添加节点间连接线但会导致Qt::ItemIsAutoTristate失效
//ui.BrowserTree->setStyle(QStyleFactory::create("windows"));

  下面是QSS样式设置。

	ui.BrowserTree->setIconSize(QSize(32, 32));
	ui.BrowserTree->setColumnCount(1);
	ui.BrowserTree->setColumnWidth(0, 300);

	QString sQssStyle = getQssStyle();
	ui.BrowserTree->setStyleSheet(sQssStyle);

	ui.BrowserTree->setHeaderHidden(true);  //隐藏表头
QString QVisualSystem::getQssStyle()
{
	QString qss = "QTreeWidget::branch:has-siblings:!adjoins-item{ \
                image:url(:/res/images/branch-line.svg) 0;\
            }\
            QTreeWidget::branch:has-siblings:adjoins-item{\
                image:url(:/res/images/branch-more.svg) 0;\
            }   \
            QTreeWidget::branch:!has-children:!has-siblings:adjoins-item{\
                image:url(:/res/images/branch-end.svg) 0;\
            }\
            QTreeWidget::branch:has-children:!has-siblings:closed,\
            QTreeWidget::branch:closed:has-children:has-siblings{\
                border-image:none;\
                image:url(:/res/images/branch-closed.svg);\
            }\
            QTreeWidget::branch:open:has-children:!has-siblings,\
            QTreeWidget::branch:open:has-children:has-siblings{\
                border-image:none;\
                image:url(:/res/images/branch-open.svg);\
            }";

	return qss;
}

2.3 属性控件QtTreePropertyBrowser

2.3.1 属性控件介绍

  Qt库封装了很多控件,种类也比较多,其中容器控件包括:表格、树和列表。使用过QtDesigner的同学应该都知道,这个工具中有一个属性编辑器,是一个属性浏览器控件,就像vs中控件属性面板一样。实际上这是Qt基于QTreeWidget封装的属性控件QtTreePropertyBrowser,虽然这个控件现在还没有被Qt正式的收录,但Qt安装包的sourc资源中附带的有源码,我们可以直接复制过来进行使用。笔者的文件位于:C:\Qt\5.15.2\Src\qttools\src\shared\qtpropertybrowser目录下。
在这里插入图片描述

2.3.2 控件用法

  拉取一个QWidget控件,然后基于控件进行提升,将控件类别提升为QtTreePropertyBrowser类型。如下所示:
在这里插入图片描述
  提升后有个编译问题,有的人可能遇到,原因跟Qt自身与VS的插件兼容性有关。假如采用的是QtCreator编辑器编码的话没有问题,但笔者使用的是VS+Qt + Qt VS Tools扩展,在VS-IDE中进行的Qt开发,因此编译出现下面报错:moc_xxxx文件使用了未定义类型“QtTreePropertyBrowserPrivate”。

1>moc_qttreepropertybrowser.cpp
1>F:\QtProject\QVisualSystem\x64\Debug\moc\moc_qttreepropertybrowser.cpp(136,29): error C2027: 使用了未定义类型“QtTreePropertyBrowserPrivate”
1>F:\QtProject\QVisualSystem\qtpropertybrowser\qttreepropertybrowser.h(48): message : 参见“QtTreePropertyBrowserPrivate”的声明
1>F:\QtProject\QVisualSystem\x64\Debug\moc\moc_qttreepropertybrowser.cpp(137,29): error C2027: 使用了未定义类型“QtTreePropertyBrowserPrivate”
1>F:\QtProject\QVisualSystem\qtpropertybrowser\qttreepropertybrowser.h(48): message : 参见“QtTreePropertyBrowserPrivate”的声明
1>F:\QtProject\QVisualSystem\x64\Debug\moc\moc_qttreepropertybrowser.cpp(138,29): error C2027: 使用了未定义类型“QtTreePropertyBrowserPrivate”
1>F:\QtProject\QVisualSystem\qtpropertybrowser\qttreepropertybrowser.h(48): message : 参见“QtTreePropertyBrowserPrivate”的声明
1>F:\QtProject\QVisualSystem\x64\Debug\moc\moc_qttreepropertybrowser.cpp(139,29): error C2027: 使用了未定义类型“QtTreePropertyBrowserPrivate”
1>F:\QtProject\QVisualSystem\qtpropertybrowser\qttreepropertybrowser.h(48): message : 参见“QtTreePropertyBrowserPrivate”的声明

  这个问题实际上是由于宏Q_OBJECT设定引起的,此处不展开说明,只说解决方式。

找到报错的头文件,右键点击打开属性设置:进行如下更改即可解决。
在这里插入图片描述

2.3.2 示例源码

在这里插入图片描述

protected slots:
	void PropertyValueChanged(QtProperty* property, const QVariant& value);

private:
	QtVariantPropertyManager* m_pEditableManager;
	QtVariantEditorFactory* m_pEditorFactory;
	QtVariantPropertyManager* m_pNotEditableManager;
	QMap<QtProperty*, QString>  m_pPropertyToValue;
void QVisualSystem::InitialPropertyTree()
{
	m_pPropertyToValue.clear();

	m_pNotEditableManager = new QtVariantPropertyManager(ui.PropertyTree);

	m_pEditableManager = new QtVariantPropertyManager(ui.PropertyTree);
	m_pEditorFactory = new QtVariantEditorFactory(ui.PropertyTree);
	ui.PropertyTree->setFactoryForManager(m_pEditableManager, m_pEditorFactory);

	// 设定字段栏的宽度
	ui.PropertyTree->setResizeMode(QtTreePropertyBrowser::ResizeToContents);

	QStringList listHead;
	listHead << QString::fromStdWString(L"字段") << QString::fromStdWString(L"值");
	ui.PropertyTree->setHeaderLabels(listHead);

	// 分组1
	QtProperty* pGroup1 = m_pNotEditableManager->addProperty(QtVariantPropertyManager::groupTypeId(), QString::fromStdWString(L"基本资料"));
	{
		QtVariantProperty* pItem = m_pNotEditableManager->addProperty(QVariant::String, QString::fromStdWString(L"姓名"));
		pItem->setValue(QString::fromStdWString(L"王无"));
		pGroup1->addSubProperty(pItem);

		pItem = m_pNotEditableManager->addProperty(QVariant::Int, QString::fromStdWString(L"年龄"));
		pItem->setValue(31);
		pGroup1->addSubProperty(pItem);

		pItem = m_pNotEditableManager->addProperty(QVariant::String, QString::fromStdWString(L"性别"));
		pItem->setValue(QString::fromStdWString(L"男"));
		pGroup1->addSubProperty(pItem);

		ui.PropertyTree->addProperty(pGroup1);
	}

	// 分组2
	QtProperty* pGroup2 = m_pEditableManager->addProperty(QtVariantPropertyManager::groupTypeId(), QString::fromStdWString(L"社会特征"));
	{
		QtVariantProperty* pItem = m_pEditableManager->addProperty(QVariant::Bool, QString::fromStdWString(L"是否在职"));
		pItem->setValue(true);
		pGroup2->addSubProperty(pItem);
		m_pPropertyToValue[pItem] = "true";

		pItem = m_pEditableManager->addProperty(QtVariantPropertyManager::enumTypeId(), QString::fromStdWString(L"学历"));
		QString sRange = QString::fromStdWString(L"本科,高中,硕士");
		QStringList enumnameslist = sRange.split(",");
		pItem->setAttribute("enumNames", enumnameslist);
		pItem->setValue(0);
		pGroup2->addSubProperty(pItem);
		m_pPropertyToValue[pItem] = "本科";

		pItem = m_pEditableManager->addProperty(QVariant::Double, QString::fromStdWString(L"从业年限"));
		pItem->setValue(3.555);
		pItem->setAttribute("decimals", 3);
		pGroup2->addSubProperty(pItem);
		m_pPropertyToValue[pItem] = "3.555";

		ui.PropertyTree->addProperty(pGroup2);
	}

	// 设定属性栏是否展开
	//QList<QtBrowserItem*> list1 = ui.PropertyTree->items(pGroup1);
	//ui.PropertyTree->setExpanded(list1.at(0), true);
}

// 相响应属性值修改变化的槽函数
void QVisualSystem::PropertyValueChanged(QtProperty* property, const QVariant& value)
{
	QString sName = property->propertyName();;
	string sMsg = "PropertyName:" + sName.toStdString() + "value:" + value.toString().toStdString();
}

3、源码下载

下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧特克_Glodon

很高兴能帮助到您!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值