简介
QtPropertyBrowser 是qt公司提供的一个关于属性设置页的解决方案。该框架的源代码在Qt的安装目录下可以找到。
QtPropertyBrowser 框架的使用比较简单。其核心或基本类有以下5个:
- Qt***PropertyBrowser(继承自QtAbstractPropertyBrowser) 属性浏览器(窗体)。
- Qt***PropertyManager(继承自QtAbstractPropertyManager)属性管理器。
- Qt***Factory(继承自QtAbstractEditorFactory)属性编辑部件工厂。
- QtProperty 表征一个属性。
- QtBrowserItem 表征属性浏览器(窗体)里面的一个属性项(或者说树结点)。
使用
第一步、创建一个属性:(如何创建一个属性?)
使用 QtProperty * QtAbstractPropertyManager::addProperty ( const QString & name = QString() ) 方法。
该属性被创建后即被添加至Qt***PropertyManager管理器实例中。
QtTreePropertyBrowser是通过Manager来管理属性的,它提供了很多类型的管理器,属性表里的属性条目,是通过Manager来创建并且管理的。因此需要创建属性时,首先需要创建一个Manager,再通过Manager来创建属性。Manager的addProperty()函数就是用于生成一个指定属性名称的属性项,同时,Manager提供了几个信号,用于告知属性的改变,它们是:propertyInserted(), propertyRemoved(), propertyChanged() 和propertyDestroyed(),
第二步、将属性添加至属性浏览器(窗体)中:(如何将一个属性添加至属性浏览器(窗体)中?)
创建了一个属性还必须将其添加至属性浏览器(窗体)中,该属性才可能在窗体中显示。
可以使用 QtBrowserItem * QtAbstractPropertyBrowser::addProperty ( QtProperty * property ) 方法。
当然,也可以使用 QtBrowserItem * QtAbstractPropertyBrowser::insertProperty ( QtProperty * property, QtProperty * afterProperty ) 插入到指定位置。
注意:一个QtProperty 属性往 QtTreePropertyBrowser 每添加(插入)一次就会生成一个唯一的QtBrowserItem(其对应属性树上的一个结点)。 因此,一个QtProperty 可以对应多个QtBrowserItem,也就是说,一个QtProperty 属性可以在属性浏览器(窗体)中对应多个结点(如果被添加或插入了多次)。
第三步、指定属性显示或编辑的控件:(如何在属性浏览器(窗体)中呈现一个属性? )
第二步中添加的属性默认的显示的控件是只读的Label,不能够编辑,通常这是不够的。如果要能够编辑(改变)属性值的话,就应该根据需要使用不同的控件来展示和编辑属性值。要用合适的控件呈现一个或一类属性,我们需要调用 void QtAbstractPropertyBrowser::setFactoryForManager ( PropertyManager * manager, QtAbstractEditorFactory * factory ) 函数来设置某个属性管理器管理的属性使用什么控件,该控件由一个控件工厂来提供。Qt***PropertyBrowser的setFactoryForManager函数,会把一个Manager和一个Factory关联起来,那么所有Manager产生的属性,都可以进行编辑。
第四步、呈现属性浏览器窗体:(如何展示属性浏览器(窗体)?)
属性浏览器QtAbstractPropertyBrowser继承自QWidget。因此利用 QWidget::show() 我们就可以看到一个属性浏览器窗口了。
非常重要的一点:属性的QtProperty层级关系。
一个QtProperty属性可以拥有0个或多个子QtProperty属性,通过 void QtProperty::addSubProperty ( QtProperty * property )添加。
疑问
不太满意或不甚了解的一点:属性浏览器对象与执行属性变化的对象之间的交互。
在实际的应用场景中,当某个属性改变值以后,具体的属性管理器(QtAbstractPropertyManager的子类)会发出一个信号:
例如,QtDoublePropertyManager类
void valueChanged ( QtProperty * property, double value );
注意:
1)发出信号的不是QtProperty 而是 QtAbstractPropertyManager的子类。
2)在接收 valueChanged ( QtProperty , double );的槽函数中需要判断发生属性值变化的是哪个QtProperty 对象? 这样一来,如果某类(某种管理器的)属性特别多的话,会导致该槽函数代码特别长;而且,由于这里需要通过属性对象的指针判断,因此属性对象指针必须被声明为成员变量,导致类的成员变量也特别的多。
3)属性浏览器(窗体)对象 需要与 执行属性变化的对象 耦合。这种耦合看起来确实不爽。如果将属性页窗体与被控制的属性对象之间通过信号-槽连接起来,但通常由于属性种类实在太多,每一个属性需要为其定义一个信号,因此需要为属性页窗体了定义太多的信号。
不知道Qt设计师是如何处理这个问题的。
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtProperty *> idToProperty;
看到QtPropertyBrowser 的例子中有用到这个映射关系的,但似乎依然解决不了我说的问题。
PS:
QtPropertyBrowser 说明文档还是比较详细的。以后使用的时候遇到问题再慢慢细读。