0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

QObject中常使用的成员函数和重要宏定义

嵌入式小生 来源:嵌入式小生 2023-02-20 09:42 次阅读

一、QObject的重要知识

QObject是Qt对象模型的核心。这个模型的核心特性是一个强大的无缝对象通信机制,即信号和槽。可以使用connect()将信号连接到槽函数,并使用disconnect()破坏已经存在的连接。为了避免永不结束的通知循环,可以使用blockSignals()暂时阻塞信号。受保护的函数connectNotify()disconnectNotify()可以用于跟踪信号连接。

Qt中,以QObject为基础形成了一棵“对象树”,当使用另一个对象作为父对象创建QObject时,该对象将自动将自己添加到父对象的children()列表中。此后父对象拥有该对象的所有权,则会自动删除析构函数中的子元素。在开发中可以使用findChild()findChildren()根据名称和可选的类型查找子对象。

每个对象都有一个objectName(),可以通过相应的metaObject()找到它的类名(函数:QMetaObject::className())。在实际开发中可以使用inherits()函数确定对象的类是否继承了QObject继承层次结构中的另一个类。当一个对象被删除时,会发出destroyed()信号,通过这一点可以捕获此信号,避免对QObject进行悬挂引用。

二、QObject重要成员函数

本小节总结在开发中,QObject中常使用的成员函数和重要宏定义。

1、事件获取和处理API
/*在此对象上安装事件筛选器filterObj*/
voidQObject::installEventFilter(QObject*filterObj)

/*这个虚拟函数接收对象的事件,如果事件e被识别并处理,则返回true*/
boolQObject::event(QEvent*e)
2、对象的线程关联API
/*返回对象所在的线程。*/
QThread*QObject::thread()const

/*更改对象及其子对象的线程关联性。如果一个对象有父对象,则不能移动该对象到另一个线程中*/
voidQObject::moveToThread(QThread*targetThread)

3、获取子对象API
/*返回该对象具有给定名称的所有可转换为类型T的子对象,如果没有此类对象,则返回一个空列表*/
QListfindChildren(constQString&name=QString(),Qt::FindChildOptionsoptions=Qt::FindChildrenRecursively)const

/*返回子对象列表*/
constQObjectList&children()const
4、qobject_cast

函数原型如下:

Tqobject_cast(QObject*object)
Tqobject_cast(constQObject*object)

如果对象类型为T(或子类),则将给定的对象转换为类型T;否则返回nullptr。如果对象是nullptr,那么它也将返回nullptr。

注意:类T必须继承(直接或间接)QObject并使用Q_OBJECT宏声明。

qobject_cast()函数的行为类似于标准c++ dynamic_cast(),它的优点是不需要RTTI(Run-Time Type Identification-运行时类型识别)支持,并且可以跨动态库边界工作。

5、事件处理相关函数
//此虚函数用于接收对象的事件,如果事件e被识别和处理,则返回true。
virtualboolevent(QEvent*e)

//如果此对象已作为被监视对象的事件过滤器安装,则过滤事件。
virtualbooleventFilter(QObject*watched,QEvent*event)

//从该对象中移除事件筛选器对象obj。
voidremoveEventFilter(QObject*obj)

//在对象上安装事件筛选器filterObj
voidinstallEventFilter(QObject*filterObj)
6、定时器相关函数
//启动计时器并返回计时器标识符
intstartTimer(intinterval,Qt::TimerTypetimerType=Qt::CoarseTimer)

//启动计时器并返回计时器标识符
intstartTimer(std::millisecondstime,Qt::TimerTypetimerType=Qt::CoarseTimer)

//使用定时器标识符id终止计时器
voidkillTimer(intid)
7、重要宏定义
  • Q_DISABLE_COPY(Class)

    禁止对给定类使用复制构造函数和赋值运算符。

  • Q_DISABLE_COPY_MOVE(Class)

该宏用于禁用给定类的复制构造函数、赋值运算符、移动构造函数和移动赋值运算符,将Q_DISABLE_COPYQ_DISABLE_MOVE组合在一起。

  • Q_DISABLE_MOVE(Class 5.13)

禁止对给定类使用移动构造函数和移动赋值操作符。

  • Q_EMIT

当希望使用第三方信号/槽函数机制来使用Qt信号和槽函数时,可以使用此宏替代emit关键字来发出信号。

  • Q_ENUM(...)

这个宏用于向元对象系统注册一个枚举类型。该宏必须放在enum声明之后,且放在具有Q_OBJECTQ_GADGET宏的类中。对于命名空间,应该使用Q_ENUM_NS()。例如:

classMyClass:publicQObject
{
Q_OBJECT

public:
MyClass(QObject*parent=nullptr);
~MyClass();

enumPriority{High,Low,VeryHigh,VeryLow};
Q_ENUM(Priority)
voidsetPriority(Prioritypriority);
Prioritypriority()const;
};
  • Q_ENUM_NS(...)

这个宏向元对象系统注册一个枚举类型。它必须放在enum声明之后,,且具有Q_NAMESPACE宏的名称空间中。与Q_ENUM相同,但在命名空间中。

  • Q_FLAG(...)

这个宏向元对象系统中注册一个单标记类型。它通常用于类定义中,以声明给定enum的值可以用作标志,并使用按位或运算符进行组合。对于命名空间,应该使用Q_FLAG_NS()。例如:

classQLibrary:publicQObject
{
Q_OBJECT

public:
...

enumLoadHint{
ResolveAllSymbolsHint=0x01,
ExportExternalSymbolsHint=0x02,
LoadArchiveMemberHint=0x04
};
Q_DECLARE_FLAGS(LoadHints,LoadHint)
Q_FLAG(LoadHint)
...
}
  • Q_INTERFACES(...)

这个宏告诉Qt这个类实现了哪些接口。在宏定义在实现插件的时候使用。例如:

classBasicToolsPlugin:publicQObject,
publicBrushInterface,
publicShapeInterface,
publicFilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID"org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface"FILE"basictools.json")
Q_INTERFACES(BrushInterfaceShapeInterfaceFilterInterface)

public:
...
};
  • Q_NAMESPACE

Q_NAMESPACE宏用于将QMetaObject功能添加到名称空间。Q_NAMESPACE可以有Q_CLASSINFOQ_ENUM_NS、Q_FLAG_NS,但不能有Q_ENUMQ_FLAGQ_PROPERTYQ_INVOKABLE、信号或槽函数。

  • Q_NAMESPACE_EXPORT(EXPORT_MACRO)

该宏的工作原理Q_NAMESPACE宏完全相同。但是,在名称空间中定义的外部staticMetaObject变量是用提供的EXPORT_MACRO限定符声明的。如果需要从动态库导出对象,该宏定义非常有用。

  • Q_OBJECT

Q_OBJECT宏必须出现在类定义的私有部分中,该类定义声明自己的信号和槽函数,或者使用Qt元对象系统提供的其他支持。

  • Q_PROPERTY(...)

此宏用于在继承QObject的类中声明属性。属性的行为类似于类数据成员,但它们具有可通过元对象系统访问的其他特性。如下代码:

Q_PROPERTY(typename
(READgetFunction[WRITEsetFunction]|
MEMBERmemberName[(READgetFunction|WRITEsetFunction)])
[RESETresetFunction]
[NOTIFYnotifySignal]
[REVISIONint]
[DESIGNABLEbool]
[SCRIPTABLEbool]
[STOREDbool]
[USERbool]
[CONSTANT]
[FINAL])
  • Q_SIGNAL

这是一个额外的宏,允许我们将单个函数标记为信号。当使用不支持信号或Q_SIGNALS组的第三方源代码解析器时,使用这个宏。

  • Q_SLOT

这是一个额外的宏,它允许将单个函数标记为槽函数。当使用不支持槽函数或Q_SLOT组的第三方源代码解析器时,使用这个宏。

三、信号和槽的连接机制注意事项

1、【自动连接(默认)】如果信号是在接收对象具有关联的线程中发出的,那么行为与直接连接相同。否则,行为与队列连接相同。

2、【直接连接】当信号发出时,槽函数被立即调用。槽函数在发射器的线程中执行,而发射器的线程不一定是接收器的线程。

3、【队列连接】当控制返回到接收方线程的事件循环时调用槽,槽函数在接收方的线程中执行。

4、【阻塞排队连接】槽被调用为排队连接,除非当前线程阻塞直到槽函数返回。

注意:使用该阻塞排队连接类型连接同一线程中的对象将导致死锁。

5、【唯一连接】与自动连接相同,但只在不复制现有连接的情况下才建立连接。也就是说,如果相同的信号已经为相同的对象连接到相同的槽,那么就不创建连接,并且connect()返回false

连接类型可以通过向connect()传递一个附加参数来指定。注意,如果事件循环运行在接收方的线程中,当发送方和接收方位于不同线程中时使用直接连接是不安全的,这与调用位于另一个线程中的对象上的函数是不安全的原因相同。

QObject::connect()本身是线程安全的。

对于队列连接,传递的参数必须是Qt元对象系统已知的类型,因为Qt需要复制参数,以便存储参数;如果参数类型不是Qt元对象系统已知的,使用队列连接,将获得错误提示信息,这时候则需要在创建连接之前,调用qRegisterMetaType()向元对象系统注册该数据类型。

四、线程关联性

在Qt中,QObject实例具有线程相关性,或者可以理解成QObject存在于某个线程中。当QObject接收到排队的信号或发布的事件时,槽函数或事件处理程序将在该对象所在的线程中运行,这一点很重要。

注意:如果一个QObject没有线程关联(也就是说,如果thread()返回0),或者如果它存在于一个没有运行事件循环的线程中,那么它就不能接收排队的信号或发布的事件。

默认情况下,QObject实例存在于创建它的线程中,在实际开发中可使用thread()查询对象的线程关联,并使用moveToThread()更改对象的线程关联。

注意:所有QObject必须与它们的父对象生活在同一个线程中。除此之外,还需要知道:

(1)如果涉及的两个QObject位于不同的线程中,setParent()将失败。

(2)当一个QObject被移动到另一个线程时,它的所有子线程也会被自动移动。

(3)如果QObject有一个父对象,moveToThread()将失败。

(4)如果QObject是在QThread::run()中创建的,它们不能成为QThread对象的子对象,因为QThread并不存在于调用QThread::run()的线程中。

QObject的父子关系必须通过传递一个指向子构造函数的指针或调用setParent()来设置。如果没有这个步骤,当调用moveToThread()时,对象的成员变量将保持在旧线程中。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1505

    浏览量

    62196
  • 函数
    +关注

    关注

    3

    文章

    4338

    浏览量

    62787
  • Qt
    Qt
    +关注

    关注

    1

    文章

    308

    浏览量

    37978

原文标题:Qt的万能承载者QObject,了解多少?

文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言定义使用技巧

    写好C语言,漂亮的定义重要,使用定义可以防止出错,提高可移植性,可读性,方便性等等。下面列举一些成熟软件
    发表于 07-29 09:35 1121次阅读

    C语言中常用的定义

    写好C语言,漂亮的定义重要,使用定义可以防止出错,提高可移植性,可读性,方便性等等。下面列举一些成熟软件
    发表于 10-18 10:05 1698次阅读

    C语言中定义的应用

    在C语言中,定义是一种预处理指令,用于在代码中定义和使用常量、函数或代码片段的替代。
    发表于 08-17 15:33 877次阅读

    C编程定义函数该如何修改?

    那么该如何修改呢?不希望写成函数形式的,写成定义形式的比较好。
    发表于 12-26 08:51

    c语言中常用的定义有哪些?

    c语言中常用的定义有哪些?
    发表于 04-28 06:01

    C语言定义使用技巧

    写好C语言,漂亮的定义重要,使用定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件
    发表于 11-13 12:04 36次下载

    内联函数定义的区别介绍

    定义是C语言提供的三种预处理功能的其中一种,这三种预处理包括:定义、文件包含、条件编译。定义
    发表于 12-15 15:33 2344次阅读
    内联<b class='flag-5'>函数</b>和<b class='flag-5'>宏</b><b class='flag-5'>定义</b>的区别介绍

    定义 “中断函数接口”的注意事项

    定义“中断函数接口”的注意事项
    的头像 发表于 03-07 16:42 2550次阅读

    ARM Linux中一些重要及地址定义

    ARM Linux中一些重要及地址定义
    的头像 发表于 06-22 17:02 2742次阅读

    一些成熟软件中常用的定义

    写好C语言,漂亮的定义重要,使用定义可以防止出错,提高可移植性,可读性,方便 性等等。 下面列举一些成熟软件
    的头像 发表于 01-18 11:21 2368次阅读

    C语言定义与预处理、函数函数

    目录前言一、C语言预处理二、定义三、函数四、函数库五、自己制作静态链接库(ubuntu 环境下,即使用Linux系统平台上的gcc)六、自己制作动态链接库(ubuntu 环境下,即使
    发表于 12-07 21:06 2次下载
    C语言<b class='flag-5'>宏</b><b class='flag-5'>定义</b>与预处理、<b class='flag-5'>函数</b>和<b class='flag-5'>函数</b>库

    类的申明和成员函数定义分离是什么

    前面我们学习了如何定义类,以及如何使用类的成员,在前面我们把成员函数定义在了类的内部,接下来我们学习,如何把类的
    的头像 发表于 02-27 15:33 964次阅读

    C语言函数封装技巧分享

    函数,即包含多条语句的定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。
    的头像 发表于 09-14 09:31 669次阅读

    列举一些C语言中常用的定义

    写好C语言,使用定义可以防止出错,提高可移植性、可读性等。下文列举一些成熟软件中常用的定义
    发表于 10-07 10:54 636次阅读
    列举一些C语言<b class='flag-5'>中常</b>用的<b class='flag-5'>宏</b><b class='flag-5'>定义</b>

    C语言中函数定义和用法

    函数是一种特殊的函数,与普通函数不同的是,它可以拥有多条语句和局部变量,从而实现更复杂的功
    发表于 10-11 11:32 3639次阅读
    C语言中<b class='flag-5'>宏</b><b class='flag-5'>函数</b>的<b class='flag-5'>定义</b>和用法