百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Qt属性系统(Qt Property System)(qt的pro文件属性说明)

zhezhongyun 2025-06-10 04:09 2 浏览

Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似。然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property 或者 [property]。Qt的解决方案能够被任何Qt支持的平台下的标准C++编译器支持。它依赖于元对象系统(Meta_Object Sytstem),元对象系统通过信号和槽提供了对象间通讯的机制。

1. Qt中怎么声明属性?

  QObject中的子类的私有域中使用Q_PROPERTY宏来声明一个属性

以下是来自QWidget类的一些属性声明
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
 
以下例子展示了如何使用MEMBER关键字将类数据成员导出为Qt属性。注,NOTIFY signal必须被指定,这样才能被QML使用
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
Q_PROPERTY(qreal spaing MEMBER m_spacing NOTIFY spaingChanged)
Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
...
signals:
void colorChanged();
void spacingChanged();
void textChanged(const QString &netText);
 
private:
QColor  m_color;
qreal     m_spacing;
QString m_text;

2. 对QT中属性的理解

  一个属性的表现就像一个普通的数据成员一样,但是它有额外提供元对象系统访问的特性

(1)如果MEMBER关键子没有被指定,则一个READ访问函数是必须的,它被用来访问数据成员的值。它的返回类型必须是属性类型或者属性类型的常引用。比如,QWidget::focus是一个只读的属性,通过读函数,QWidget::hadFocus访问。

(2)一个WRITE函数是可选的,它被用来设置数据成员的值。的返回类型必须是void,而且仅能有一个参数,其类型必须是属性类型或者是属性类型的指针类型或者是属性类型引用。例如,QWidget::enabled有一个WRITE函数,QWidget::setEnabled(bool)。只读属性不需要WRITE函数。比如QWidget::focus就没有WRITE函数。

(3)如果属性没有READ访问函数,则需要用MEMBER指定成员变量,这使得给定的成员变量在没有创建READ和WRITE的函数下可读可写。如果你需要控制变量的访问权限,也可以使用READ和WRITE函数而不仅仅是MEMBER,注意别同时使用。

(4)一个RESET函数页是可选的,它被用来将属性设置为上下文指定的默认值,例如,QWidget::cursor有READ和WRITE函数,QWidget::cursor() QWidget::setCursor(),同时它也有一个RESET函数QWidget::unsetCursor(),因为没有可用的setCursor调用可以确定的将cursor属性重置为上下文默认的值。RESET函数必须返回void类型,而且不带参数。

(5)NOTIFY也是可选的。如果定义了NOTIFY则需要指定一个已经存在的信号,该信号在属性值发生改变是发射。与属性相关的信号必须有一个或者零个参数,而且必须与属性的类型相同。参数为数据成员的新值。NOTIFY信号应该仅仅当属性值真正的发生改变时发出,以避免被QML重新评估。

(6)REVISION也是可选的,如果包含了该关键字,它定义了该属性和信号被特定版本的API使用通常是QML。如果没有包含该关键字其默认为0。

(7)DESIGNABLE指定了该属性在GUI编辑器中是否可见(比如QtDesigner)。大多数的属性是可设计的(DESIGNABLE默认为真)。除了true和false,你还可以指定boolean成员函数。

(8)SCRITABLE属性指定了该属性是否可以被script engine访问,其默认为真。除了true和false你还可以指定boolean函数。

(9)STORED属性指定了该属性是否是独立的或者是否依赖于别的属性。它也指定了当保存对象属性时是否会保存该属性。大多数的属性的STORED为真。但是,QWidget::minmunWidth()的STROED为false,因为它的值是从QQWidget::minimumSize()中取得的,它的类型是QSize。

点击领取Qt学习资料+视频教程~

「链接」

(10)USER指定了属性是否被设计为用户可见和可编辑的。正常情况下,每一个对象只用一个USER属性(默认为false)。例如,QAbstractButton::clicked对Buttons是可编辑的(checkable)。注,QItemDelegate使用设置和访问函数色设置widget的USER属性。

(11)CONSTANT的出现表明属性是一个常量值。对于给点的对象实例,每一次READ函数的调用都应该返回相同的值。对于不同的实例该属性可能会不相同。同时不能有WRITE函数和NOTIFY信号。

(12)FINAL表明该属性不会再子类中被覆盖。在某些情况下它被用来优化性能,但是并没有被moc实现。必须注意,绝不在子类中覆盖FIANL属性。

(13)READ WRITE RESET函数可以被继承。它们也可以是虚函数。当在使用多继承的类中使用的时候,其必须来自第一个类。

属性类型可以是任何QVariant支持的属性,或者是用户自定义的属性。在这个例子中,类QDate被看做用户自定义的类型。Q_PROPERTY(QDate data READ getDate WRITE setDate)因为QDate是用户自定义的,当声明属性时,你必须包含<QDate>头文件。由于历史原因,QMap和QList是QVariantMap和QVariantList的同义词。

3. 使用元对象系统读写属性

  一个属性可以通过QObject::poperty()函数、QObject::setProperty()函数访问和设置。除了属性的名字之外不用知道类的别的信息。在下面的代码段中,调用函数QAbstractButton::setDown()和函数QObject::setProperty()都是设置属性“down”

QPushButton* button = new QPushButton;
QObject* object = button;
button->setDown(true);
object->setProperty("down" , true);

  通过WRITE函数设置属性值,比上述两者都好,因为它效率更高而且在编译时期有更好的诊断。但是这需要你在编译实际了解整个类(能够访问其定义)。通过属性名访问属性,能够让你再不了解类的定义的情况访问或者设置属性。你可以在运行时期通过QObject,QMetaObject和QMetaProperties查询类属性。

QObject *object = ...
const QMetaObject *metaObject = object->metaObject();
int count = metaObject->propertyCount();
for (int i = 0 ; i< count; ++i) {
    QMetaProperty metaProperty = metaObject->property(i);
    cont char *name = metaProperty.name();
    QVariant value = object->property(name);
}

  在上述的代码片段中,QMetaObject::property()被用来获取定义在某个未知的类中的metaData。属性的名称通过metaData获取,并且将其传给QObject::property()来获取属性值。

  假设我们有一个简单的类MyClass,它继承自QObject而且在private域中使用了Q_OBJECT。我们想声明一个属性用于跟踪权限值。该属性的名称是priority,它的类型是定义在MyClass中的Priority枚举。

点击领取Qt学习资料+视频教程~

「链接」

  我们使用Q_PROPERTY在private区里声明属性。READ函数是priority(),WRITE函数是setPriority()。枚举类型需要使用Q_ENUM()宏将其注册到Meta-Object System中。注册一个枚举类型使得枚举可以在setPropert函数中使用。我们也必须提供READ和WRITE函数的声明。该类的定义如下:

class MyClass : public QObjct
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();
 
    enum Priority { High , Low , VeryHigh , VeryLow };
    Q_ENUM(Priority)
 
    void setPriority(Priority priority)
    {
        m_priority = priority;
    }
 
    Priority priority() const { return m_priority; }
 
signals:
    void priorityChanged(Priority);
 
private:
    Priority m_priority;
};

  READ函数是常成员函数而且返回Priority类型。WRITE函数返回void而且只有一个类型为Priority的参数。

  给定一个指向MyClass实例的类型为MyClass或者QObject的指针,我们有两种方式去设置它的priority属性。

MyClass *myinstance = new MyClass;
QObject *object = myinstance;
 
myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority" , "VeryHigh");

  在这个例子中,定义在MyClass中的枚举类型是属性的类型,而且被Q_ENUM()宏注册在Meta-Object System中。这使得枚举类型可以在setProperty中通过字符串访问(string),使用在别的类中定义的枚举类型,他必须被完全的声明(i.e. OtherClass::Priority)。而且那个类应该继承自QObject而且使用Q_ENUM()宏注册。

一个相似的宏Q_FLAG()。就像Q_ENUM()一样,它注册枚举类型,但是将其标记为一系列的flag,即,可以使用或操作。一个IO类有着Read和Write的枚举值,而且之后可以在QObject::setProperty传入Read | Write访问。Q_FLAG()应该被用来注册枚举类型。

4. 动态属性

  QObject::setProperty()也可以被用来在运行时期为类实例添加属性。当传入名称和值调用该函数时。如果属性名称已经在类中存在并且传入的类型与属性的类型兼容,则属性值被保存并且返回真,否则值不会被修改,但是函数返回假。但是如果给定的属性名不存在则新的属性被添加到类中,当函数仍然返回false。这意味着函数的返回值不能用来确定属性值看是否被成功的设定。除非你已经知道属性之前是否存在。

  注:动态属性被添加到每一个实例中。即它们被添加到QObject中而不是QMetaObject中。可以通过传递一个空的QVariant给setProperty函数来移除属性。QVariant的默认构造函数构造一个无效的QVariant对象。

  动态属性可以通过QObject::property()查询,就像Q_PROPERTY定义的属性一样。

  被属性使用的自定义类型需要使用Q_DECLARE_METATYPE宏注册。这样QVariant对象才能够保存该类的值。这个在动态和静态属性都是适用的。

点击领取Qt学习资料+视频教程~

「链接」

  为类添加额外的信息与属性系统相对应的是Q_CLASSINFO(name , value)宏。这个宏将添加name-value的到类的元对象中。例如:

  Q_CLASSINFO(“Version” , “3.0.0”)

  和被使用的元对象数据一样,类信息可以在运行时通过QMetaObject::classInfo函数访问。

附:所谓添加属性到QOject中二不是QMetaObject中的意思是:
假设:有两个MyClass对象的实例a 与 b,当为a动态添加一个属性时,b是不会受到影响的。
QMetaObject是所有的MyClass实例所共享的。
关于Q_DECLARE_METATYPE,另一个重要的用途就是用于注册信号和槽中使用的用户自定类型。
如果信号和槽使用Qt::QueuedConnection连接,则还需要使用qRegisterMetaType<T>()函数注册。
此外,Qt的状态机框架和动画框架依赖属性系统。

相关推荐

屏幕属性详解:DCI-P3、对比度、色域、Nit

屏幕属性详解:DCI-P3、对比度、色域、Nit---一、DCI-P3(色域标准)1.定义DCI-P3是由美国电影工业制定的广色域标准,覆盖CIE1931色彩空间的约96%,尤其强化红色和绿...

Qt属性系统(Qt Property System)(qt的pro文件属性说明)

Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似。然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property或者[property]。Qt的解决方案...

用 Cursor 开发 10 +项目后,汇总了40 多条提示词

每次跟新手讲解Cursor的使用技巧时,他们总会说:"哎呀,这工具好是好,就是不知道该怎么跟它对话..."是的,不少小伙伴都在为这个困扰:手握着强大的AI编程工具,却像拿着一把...

Excel常用技能分享与探讨(5-宏与VBA简介 VBA与数据库)

在VBA(VisualBasicforApplications)中使用数据库(如Access、SQLServer、MySQL等)具有以下优点,适用于需要高效数据管理和复杂业务逻辑的场景:1....

汽车诊断协议J1850-VPW 测试(汽车诊断协议工程师干啥的)

硬件说明:MCU:GD32C103120M,128K,32kRAM.输入:USB5V.OBD功能口定义:OBD(2,10)VPWM、OBD7(K线)、OBD6(CANH)、OBD14(...

ssl证书有哪些类型?有什么区别?(ssl证书的区别)

以下是**Windows服务器常用快捷命令大全(100条)**,涵盖系统管理、网络诊断、安全维护、文件操作等场景,适合管理员快速操作和故障排查:---###**一、系统信息与配置**1.**`s...

嵌入式工程师竟然看不懂这些专业语句,那真别怪人说你菜

本文出自公众号:硬件笔记本,原创文章,转载请注明出处AASIC(专用集成电路)Application-SpecificIntegratedCircuit.Apieceofcustom-de...

同星提供SecOC信息安全解决方案(上海同星)

需求背景在传统的汽车电子结构中,车内的电控单元(ECU)数量和复杂性受到限制,通信带宽也受到限制。因此,人们普遍认为车内各个ECU之间的通信是可靠的。只要ECU节点接收到相应的消息,就会对其进行处理。...

H3C MSR系列路由器EAA监控策略配置举例

1简介本文档介绍使用EAA监控策略进行网络监控的典型配置举例。2配置前提本文档适用于使用ComwareV7软件版本的MSR系列路由器,如果使用过程中与产品实际情况有差异,请参考相关产品手册,或以...

网卡DM9000裸机驱动开发详解(网卡驱动9462)

一、网卡1.概念网卡是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件。由于其拥有MAC地址,因此属于OSI模型的第2层。它使得用户可以通过电缆或无线相互连接。每一个网卡都有一个被称为MA...

如何检验自己的手机有没有问题,实操干货!包学会

此贴供已购买二手苹果或正打算购买的朋友参考,已入新机的朋友也可以验一下你的手机有没有问题。无废话,直接上干货以小编随机挑的一台12为例1.外观:拿到手机先看整体外观,是否与商家描述的外观一致,磕碰和划...

再不看就删了!超详细的Ribbon源码解析

Ribbon简介什么是Ribbon?Ribbon是springcloud下的客户端负载均衡器,消费者在通过服务别名调用服务时,需要通过Ribbon做负载均衡获取实际的服务调用地址,然后通过httpcl...

细数ThreadLocal三大坑,内存泄露仅是小儿科

我在参加CodeReview的时候不止一次听到有同学说:我写的这个上下文工具没问题,在线上跑了好久了。其实这种想法是有问题的,ThreadLocal写错难,但是用错就很容易,本文将会详细总结Thre...

微服务架构下的Java服务监控:让程序“健康自检”不再难

微服务架构下的Java服务监控:让程序“健康自检”不再难引言:为什么需要服务监控?在微服务架构的世界里,我们的系统由众多小型且独立的服务组成。想象一下,这些服务就像一群跳舞的小精灵,在各自的舞台上表演...

6. 并发编程(并发编程模型)

本章深入解析Go语言并发编程核心机制,涵盖调度原理、通信模式及工程实践,结合性能优化与陷阱规避策略。6.1Goroutine基础6.1.1创建与调度//启动goroutinegofunc()...