QT面试必备知识
创始人
2024-03-04 03:35:00
0

QT面试必备知识

    • QObject
      • QObject与多线程
        • QObject的依附线程
        • QObject是否是线程安全的
        • QThread
        • QObject的线程依附性是否可以改变
        • 如何安全的在另外一个线程中调用QObject对象的接口
    • 事件
      • 事件循环
        • 主事件循环
      • notify
      • sendEvent
      • postEvent
      • deleteLater
    • 信号槽
      • 信号重载了,如何确定连接哪个信号?
      • 槽函数参数、信号的参数
      • 槽函数的参数是否可以比信号的参数多?

QObject

完整看一遍:线程和 QObject

QObject与多线程

QObject的依附线程

  • QObject::thread()可以查询一个QObject的线程依附性。每一个QObject对象或者子对象,都拥有一个记录所依附线程的成员数据:QThreadData threadData,记录了拥有这个QObject对象的线程ID号。
  • 一个QObject的所依附的线程(thread affinity)是指它所在的那个线程,即QObject对象创建的那个线程。
  • 线程的事件循环会给依附在这个线程上的所有QOjbect对象派发事件。
  • Qt 要求QObject的所有子对象都必须和其父对象在同一线程。
    因此不能在QThread中以这个QThread本身作为父对象创建对象,例如:
class Thread : public QThread {void run() {QObject *obj = new QObject(this); // 错误!}
};

QObject是否是线程安全的

QObject及其所有子类都不是线程安全的(但都是可重入的)。因此,你不能有两个线程同时访问一个QObject对象,除非这个对象的内部数据都已经很好地序列化(例如为每个数据访问加锁)。

QThread

这里有两个概念:

  • QThread对象所在的线程 —— 创建QThread对象所在的那个线程,而不是创建的那个子线程
  • QThread对象所管理的线程 —— 真正创建的那个子线程
  • 线程的事件循环用于为线程中的所有QObjects对象分发事件;默认情况下,这些对象包括线程中创建的所有对象,或者是在别处创建完成后被移动到该线程的对象。

QObject的线程依附性是否可以改变

调用QObject::moveToThread()函数。该函数会改变一个对象及其所有子对象的线程依附性。

  • 由于QObject本身是线程不安全的,因此moveToThread接口的调用必须在QObject对象所在的线程内调用。

如何安全的在另外一个线程中调用QObject对象的接口

QObject被设计成在一个单线程中创建与使用,因此,在一个线程中创建一个对象,而在另外的线程中调用它的函数,这样的行为不能保证工作良好。

  • 使用信号槽的队列连接或者QT的反射系统提供的QMetaObject::invokeMethed的队列连接调用。这要求接口必须是内省的,也就是说这个函数要么是一个槽函数,要么标记有Q_INVOKABLE宏。
  • 将事件提交到接收对象所在线程的事件循环;当事件发出时,响应函数就会被调用。

事件

事件循环

主事件循环

int QCoreApplication::exec()

主事件循环接收来自系统的事件,并转换为QT的事件消息,并把这些事件分发到对应的应用程序窗口上。

notify

bool QCoreApplication::notify(QObject *receiver, QEvent *event)
  • 把事件发送到receiver的事件处理函数{receiver}->event(event)中
  • 如果接收者receiver对event事件不感兴趣,事件则会传递给receiver的父对象,直到顶级对象的事件处理函数中。

5种处理事件的方法:

  • 1、重写QObject的事件处理函数mousePressEvent
  • 2、重写QCoreApplication::notify 拥有完整的控制
  • 3、给QCoreApplication::instance()安装一个事件过滤器,因此事件过滤器里能处理所有控件的所有事件,控制强度跟notify一样。
  • 4、重写QObject::event()
  • 5、给一个QObject对象安装一个事件过滤器,这个事件过滤器则会处理这个QObject对象的所有事件。

sendEvent

bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
  • 使用notify函数,直接把事件给到接受者
  • event最好是栈空间,sendEvent不会删除event对象。

postEvent

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)

把事件event投递到对象receiver所在事件队列中,并立即返回。

  • 线程安全的QCoreApplication::postEvent()函数向一个对象发送事件。它将把事件加入到对象所在的线程的事件队列中,因此,如果这个线程没有运行事件循环,这个事件也不会被派发。
  • event必须在堆上分配,因为postEvent会获取event的所有权,并把原始的event删除。
  • 当控制返回到主事件循环,那么所有存储在事件队列中的一个个事件将会被调用notify函数分发出去。
  • 事件队列中的事件按事件优先级降序排序,即高优先级的事件在队头。
  • 这个接口是线程安全的

deleteLater

对于deleteLater的用法,官方描述如下:

    The object will be deleted when control returns to the eventloop. If the event loop is not running when this function iscalled (e.g. deleteLater() is called on an object beforeQCoreApplication::exec()), the object will be deleted once theevent loop is started. If deleteLater() is called after the main event loophas stopped, the object will not be deleted.Since Qt 4.8, if deleteLater() is called on an object that lives in athread with no running event loop, the object will be destroyed when thethread finishes.

实现如下:

void QObject::deleteLater()
{QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}

它是线程安全的删除QObject对象的方法。

  • 分析下deleteLater调用后的过程
    Aobj->deleteLater()相当于QCoreApplication::postEvent(Aobj, new QDeferredDeleteEvent());,把一个QDeferredDeleteEvent事件投递到了Aobj所依附的线程的事件队列中,等Aobj所依附的线程的事件循环获得控制权时,删除Aobj对象。

Qobj->deleteLater()调用后,Qobj这个对象真正被执行删除的时候是在(当前这个线程?)重新回到事件循环的时候处理的。如果在事件循环未启动前就调用deleteLater,那么这个对象会在事件循环一启动就会被删除。如果在事件循环结束后,再调用deleteLater,那么这个对象将不会被删除。
如果在一个子线程中,这个子线程没有运行事件循环,那么这个对象的删除,将在子线程结束时删除。而对于整个程序而言,主线程都会有事件循环(因为,return QApplication::exec()),所以主线程中删除对象不会存在这个情形。

  • 一个对象调用deleteLater后,再调用它的接口,是否会有问题
    不会有问题。不会立刻删除对象,直到进入事件循环

信号槽

参考:https://www.kancloud.cn/kancloud/qt-study-road-2/99456

信号重载了,如何确定连接哪个信号?

答,采用函数指针确定连接哪个信号。

槽函数参数、信号的参数

槽函数的参数可以少于信号的参数。

  • 槽函数本身参数比信号的少
  • 槽函数参数带有默认参数

槽函数的参数是否可以比信号的参数多?

也可以。唯一的情况就是槽函数参数带有默认参数,除去默认参数外,槽函数的参数必须小于等于信号的参数。

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...