草庐IT

QT必备知识

上官宏竹 2023-10-01 原文


QT必备知识

参考:深入理解Qt

moc实现原理

Q_OBJECT的作用是什么,内部实现了些什么

Q_OBJECT 是 Qt 框架中的一个宏定义,用于在类的声明中标记该类需要使用 Qt 的元对象系统(Meta-Object System)。使用 Q_OBJECT 宏定义后,编译器会在编译期自动生成元对象代码,包括信号(signal)和槽(slot)的注册、元对象信息的注册等等。

具体来说,使用 Q_OBJECT 宏定义后,编译器会为该类生成一个 QMetaObject 对象,该对象包含了该类的元对象信息,包括类名、信号和槽的名称、参数类型等等。这些信息可以通过 QObject::metaObject() 函数获取到。

此外,使用 Q_OBJECT 宏定义后,还可以在该类中使用信号和槽,使用 emit 关键字来发射信号,使用 connect 函数将信号和槽连接起来。这些功能都是通过 Qt 的元对象系统实现的。

需要注意的是,使用 Q_OBJECT 宏定义的类必须直接或间接继承自 QObject 类。

  • 实现原理
    Q_OBJECT 宏定义会为该类自动添加一些成员变量和成员函数,用于支持 Qt 的元对象系统。
  • 1、 QObject 类的虚函数 metaObject(),它返回一个描述该对象的元对象。
  • 2、QMetaObject 类型的静态变量,用于存储该对象的元对象。

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宏。
  • 将事件提交到接收对象所在线程的事件循环;当事件发出时,响应函数就会被调用。

事件

重点阅读:深入理解Qt——事件循环

QEventLoop::exec

用法1:

void widget::on_pushButton_clicked()
{
........ 需要等待100毫秒的时间.等待某个条件成立
    //事件循环: 在指定时间后执行某件事. 不卡UI界面
    QEventLoop loop;
    QTimer::singleShot(100, &loop, SLOT(quit()));
    loop.exec();
.........
继续执行代码.
}

用法2:

QEventLoop loop;
void widget::on_pushButton1_clicked()
{
........ 需要等待某个条件成立
    loop.exec();
.........
继续执行代码.
}

//槽函数: 等待的条件满足时进入
void widget::on_timeclicked()
{
..........
loop.exit();  //退出事件循环
}

为何在通过QEventLoop::exec()阻塞程序执行,程序却不会卡死

因为QEventLoop::exec()开启了一个新的事件循环来分发事件,而且相同线程上的所有事件循环采用同一个事件调度器。

事件循环

主事件循环

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 event
    loop. If the event loop is not running when this function is
    called (e.g. deleteLater() is called on an object before
    QCoreApplication::exec()), the object will be deleted once the
    event loop is started. If deleteLater() is called after the main event loop
    has stopped, the object will not be deleted.
    Since Qt 4.8, if deleteLater() is called on an object that lives in a
    thread with no running event loop, the object will be destroyed when the
    thread 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后,再调用它的接口,是否会有问题
    不会有问题。不会立刻删除对象,直到进入事件循环

模型/视图机制

QT 中的模型/视图机制是一种用于管理数据的框架,可以将数据和其显示方式分离,并提供一种通用的接口来访问和操作数据。在 QT 中,模型/视图机制通常使用 QAbstractItemModel、QAbstractListModel、QAbstractTableModel 等类来实现。

模型负责提供数据,视图负责将数据显示在界面上,并允许用户进行操作。视图通常包括 QListView、QTableView、QTreeView 等类,用于显示不同类型的数据。当模型数据发生变化时,模型会自动发送信号给视图,并通知视图进行更新。同时,视图也可以通过发送信号给模型来请求数据,例如获取某一行、某一列的数据等。

QT 中的模型/视图机制支持多种不同的数据源,例如内存中的数据、数据库中的数据、XML 文件中的数据等。此外,QT 中还提供了一些常用的模型实现,例如 QDirModel、QFileSystemModel、QStandardItemModel 等,用于快速创建常见的数据模型。

QFrame与QWidget的区别

QFrame 和 QWidget 都是 Qt 中的 GUI 组件,但是它们有一些区别:

继承关系:QFrame 继承自 QWidget,所以 QFrame 具有 QWidget 的所有功能。

功能:QFrame 提供了一个简单的框架,可以作为其他控件的容器。它还可以用来绘制简单的图形,如线条。QWidget 没有这样的功能,但是提供了基础的 GUI 组件功能,如设置尺寸和位置等。

外观:QFrame 可以有边框和背景颜色,因此外观更加丰富。QWidget 只有背景颜色,没有边框。

通常,当需要一个简单的框架时,使用 QFrame,当需要基础的 GUI 组件功能时,使用 QWidget。

信号槽

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

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

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

槽函数参数、信号的参数

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

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

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

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

什么是 QT?QT 的优势是什么?
QT 的事件机制是什么?什么是事件循环?
QT 中的信号和槽是什么?如何使用信号和槽连接不同的对象?
QT 中的多线程机制是什么?如何在 QT 中使用多线程?
QT 中常用的布局管理器有哪些?如何使用布局管理器来布置窗口控件?
QT 中的界面控件有哪些?如何使用界面控件来实现特定的功能?
QT 中如何实现自定义控件?
QT 中的文件系统和网络编程是如何实现的?如何使用 QT 进行文件读写和网络通信?
QT 中如何进行国际化和本地化?
QT 中如何进行调试和性能优化?
当然,除了这些问题,面试官可能还会问到一些其他的 QT 相关问题,比如 QT 中的绘图机制、动画效果、插件机制等等。建议在面试前认真复习 QT 的相关知识点,并做好充分的准备。

隐式共享


有关QT必备知识的更多相关文章

  1. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  2. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  3. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  4. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  5. Linux网络编程必备的POSIX API的细节 - 2

    目录POSIXAPI大集合五元组三次握手的过程,内核协议栈分析listen函数DDOS攻击,洪水攻击DDOS攻击的应对措施数据发送 怎么保证顺序?如何保证包地顺序到达(序号+确认应答机制+重传)TCP断开连接的过程问题1.大量的CLOSE_WAIT+FIN_WAIT2是为啥?time_wait状态存在的原因?POSIXAPI大集合五元组(sip,sport,dip,dport,protocol)三次握手的过程,内核协议栈分析内核协议栈中是有内核数据结构的.  我们send/write数据,都是先发送到内核协议栈中,然后由内核协议栈封装发送到物理介质中传输到对端的对端的接收过程也是经有内核协议栈

  6. ruby - Ruby基础知识 - 2

    Asitcurrentlystands,thisquestionisnotagoodfitforourQ&Aformat.Weexpectanswerstobesupportedbyfacts,references,orexpertise,butthisquestionwilllikelysolicitdebate,arguments,polling,orextendeddiscussion.Ifyoufeelthatthisquestioncanbeimprovedandpossiblyreopened,visitthehelpcenter提供指导。已关闭8年。什么是学习ruby语言

  7. 科研中论文常见数学符号及其含义(科研必备,建议收藏) - 2

    论文常见数学符号及其含义(科研必备)返回论文和资料目录数学符号在数学领域是非常重要的。在论文中,使用数学符号可以使得论文更加简洁明了,同时也能够准确地描述各种概念和理论。在本篇博客中,我将介绍一些常见的数学符号及其含义(省去特别简单的符号),希望能够帮助读者更好地理解数学论文。高等数学∑i=1nxi\sum_{i=1}^nx_i∑i=1n​xi​(求和符号):表示将x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x2​,…,xn​中的所有数相加,例如∑i=1nxi\sum_{i=1}^nx_i∑i=1n​xi​表示将x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x

  8. Qt样式表之 QSS 语法介绍;QLineEdit、 - 2

     内容来自Qt样式表之QSS语法介绍-3YL的博客Qt样式表是一个可以自定义部件外观的十分强大的机制,可以用来美化部件。Qt样式表的概念、术语和语法都受到了HTML的层叠样式表(CascadingStyleSheets, CSS教程)的启发,不过与CSS不同的是,Qt样式表应用于部件的世界。类型选择器QPushButton匹配QPushButton及其子类的实例ID选择器QPushButton#okButton匹配所有objectName为okButton的QPushButton实例。 CSS常用样式1CSS文字属性注:px:相对长度单位,像素(Pixel)。pt:绝对长度单位,点(Point

  9. QT 设计一个串口调试工具,用一个工程就能轻松解决,外加虚拟串口工具模拟调试,在日常工作中可类比模块间通信,非常详细建议收藏 - 2

    QT串口调试工具第一节虚拟串口工具安装第二节QT创建一个基于QWidget的项目第三节UI界面设计第三节项目头文件widget.h第四节项目实现文件widget.cpp第五节main函数第六节编译结果重点第七节使用QT打包程序,不安装QT的电脑可使用第一节虚拟串口工具安装-----------------------------------------下载所需工具---------------------------------------------------------------------链接:https://pan.baidu.com/s/1QkT36S4EnH2HEAhZ1TZ8

  10. 嵌入式学习之QT学习----3 制作简单的QT界面(如:QQ登录界面) - 2

    1、创建一个QT工程newproject—>Application—>QtWidgetsApplication—>choose…(注意不要有中文路径)填写名称(我写的名称为class2)和创建路径(D:\qt\qt_demo\class2)—>填写类名,这里基类要选择“QWidget”,这样一个QT工程就创建好啦。qt的移植性非常强,一套代码我们不用修改太多,直接通用所有的平台。说明:QMainWindow:主窗口类,主窗口具有主菜单栏、工具栏和状态栏,类似于一般的应用程序的主窗口。QWidget:它是所有具有可视界面的基类,选择QWidget创建的界面对各种界面组件都可以支持。QDialog

随机推荐