在 Qt 框架中,QtPropertyBrowser模块提供了一种方便的方式来编辑对象的属性。
QtPropertyBrowser从Qt 4.x版本开始就被包含在Qt工具中,在Qt5中进行了更新和适配,确保Qt5的兼容性,但并未直接作为一个独立的DLL编译,而是包含在Qt工具中,具体位置:qttools\src\shared\qtpropertybrowser

Qt模块介绍

这个模块主要涉及四个核心组件:QtAbstractPropertyBrowser, QtAbstractPropertyManager, QtAbstractPropertyFactory, 和 QtProperty。下面详细解释每个组件的作用和意义,以及它们之间的相互关系:

1. QtProperty

QtProperty 是一个抽象类,它表示一个可以被编辑的属性。这个类本身不涉及任何具体的数据类型或值的管理,而是作为一个通用的属性接口。在实际使用中,它被用来构建和维护属性的结构和层次关系。

作用:

  • 表示一个单独的属性项。
  • 维护属性的层次关系(例如,一个属性可以有子属性)。

2. QtAbstractPropertyManager

QtAbstractPropertyManager是负责管理特定类型属性的值和行为的抽象基类。对于每种数据类型(如整数、浮点数、颜色等),都有一个相应的QtXXXPropertyManager实现,这些实现继承自QtAbstractPropertyManager。每个QtAbstractPropertyManager负责存储具体属性的值,处理值的变更,并发出相应的信号。

类型

  1. QtGroupPropertyManager:负责管理分组属性,可以任意添加QtProperty对象作为该分组的子属性。
  2. QtVariantPropertyManager:负责管理QVariant类型的属性值。

还要其他很多类型,比如QtIntPropertyManagerQtDoublePropertyManagerQtTimePropertyManagerQtColorPropertyManager等,这些类型在应用时可以不用关注,这里就不详细介绍了。

作用

  • 管理具体的属性值(例如,整数、字符串、颜色等)。
  • 提供接口来设置和获取属性值。
  • 发送属性值变化的信号。

3. QtAbstractPropertyFactory

QtAbstractPropertyFactory是一个抽象类,负责为QtProperty生成相应的编辑器控件。每种 PropertyManager都可以有一个对应的PropertyFactory实现,这个工厂基于管理的属性类型来创建适当的编辑器控件。

作用:

  • 为QtProperty提供具体的编辑器控件。
  • 根据属性的类型创建适合的 UI 组件。

4. QtAbstractPropertyBrowser

QtAbstractPropertyBrowser是一个容器控件,用于显示和编辑通过QtPropertyManager管理的属性。它使用QtAbstractPropertyFactory来为每个属性创建相应的编辑器控件。QtAbstractPropertyBrowser可以是基于树的浏览器(QtTreePropertyBrowser)、基于组的浏览器(QtGroupBoxPropertyBrowser)等形式。

作用:

  • 作为用户界面,显示属性列表。
  • 使用与QtXXXPropertyManager关联的QtXXXPropertyFactory来为属性创建编辑器,从而允许用户编辑属性值。

相互关系

这四个组件协同工作,以提供一个完整的属性编辑功能:

  • 属性定义QtProperty实例定义了要显示的属性。
  • 属性管理QtXXXPropertyManager负责管理QtProperty实例的值,包括获取和设置值。
  • 编辑器生成QtAbstractPropertyFactory根据QtPropertyManager管理的属性类型,为每个属性生成相应的编辑器控件。
  • 显示和编辑QtAbstractPropertyBrowser使用PropertyFactory创建的编辑器来显示和允许用户编辑PropertyManager中的属性值。

代码测试

我们先看效果:

效果

1y82s-qhki6.gif

UI

image.png
UI是由两个QListWidget和一个Widget组成的,其中Widget需要提升为QtTreePropertyBrowser类,作为属性栏控件;左边的QListWidget需要添加两个Item用来切换,每次切换通知属性栏更新显示;底部的QListWidget是通过属性栏修改对象属性值成功后的结果。

关键代码解释

切换显示更新

QtTreePropertyBrowser在更新时需要通过以下两个步骤:

  1. clear()

清除当前属性树控件的所有属性。

  1. addProperty()

添加属性QtProperty进行显示。

因为每次都需要添加QtProperty来进行显示,那么程序就需要一直维护所有数据类型的属性节点,但你不可能把所有属性节点一一维护起来,每次更新的时候一一添加进去。怎么解决?

初始化管理属性关系

因为每次切换的时候需要调用QtTreePropertyBrowser::addProperty()来显示,那么我就把每一种数据类型的多个属性整合在两三个分组属性下,后面切换更新时只需添加这两三个分组属性即可。

auto factor = new QtVariantEditorFactory();
auto manager = new QtVariantPropertyManager();
// 分组1
auto objItem = manager->addProperty(QtVariantPropertyManager::groupTypeId(), tr("Object"));
auto objNameItem = manager->addProperty(QVariant::String, tr("ObjectName"));
objItem->addSubProperty(objNameItem);
auto metaObj = object->metaObject();
// 分组2
auto styleItem = manager->addProperty(QtVariantPropertyManager::groupTypeId(),
                                      metaObj->superClass()->className());
for (int i = 1; i < metaObj->propertyCount(); ++i) {
    auto    property = metaObj->property(i);
    QString propertyName = property.name();
    auto    item = manager->addProperty(property.type(), propertyName);
    styleItem->addSubProperty(item);
}

这里我通过Qt元对象系统中的元对象数据来遍历对象的属性,然后一一添加到对应的分组中。

QSS样式表

QtPropertyEditorView {
    border: 1px solid #a0a0a0;
    background-color: #f0f0f0;
}

QtPropertyEditorView::item {
    border: none;
    background-color: #f0f0f0;
    margin-top: 1px;
    margin-bottom: 1px;
    padding: 5px;
    font-size: 14px;
}

QtPropertyEditorView::item:selected, QtPropertyEditorView::branch:selected{
	background-color: #1b84d7;
    color: black;
}


QtPropertyEditorView QHeaderView::section {
    background-color: #c0c0c0;
    border: 1px;
    color: #292727;
    font-size: 18px;
    font-weight:bold;
}

注意
属性树控件是用QTreeWidget实现的,但是在写QSS时不能用QTreeWidget来匹配,通过源码可以知道QtPropertyEditorView类是继承QTreeWidget的,所以直接用QtPropertyEditorView来匹配。

代码链接

LeoLei8060@github.com
LeoLei8060@gitee.com

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐