QApplication与QCoreApplication

2023-10-26

QApplication (GUI 程序中 有且仅有一个)

QApplication 类 管理GUI程序的控制流和主设置。

QApplication 包含主事件循环。所有来自窗口系统和其他源的事件将被处理和分配。它也处理程序的初始化,析构和提供会话管理。

对于非GUI的用QCoreApplication 代替QApplication,它不依赖QtGui库。

qApp是一个全局的指针,指向QApplication的对象。

QApplication的主要职责如下:

1,初始化程序的用户桌面设置,如palette(),font(),doubleClickInterval()(鼠标双击的时间间隔),并一直监视这些属性,以防用户改变他们(得到及时的更新)。

2,处理事件,意思是它接收来自底层窗口系统的事件,并把他们分发给关联的窗口,通过sendEvent(),postEvent(),你可以把你自己的事件发给部件。

3,解析命令行参数。

4,定义程序的观感(被封装在QStyle 对象中)。通过setStyle()可以实时的改变。

5,它知道程序的窗口信息。可以通过widgetAt(),还可以得到一个窗口列表通过topLevelWidgets(),然后通过closeAllWindows()关闭所有窗口。

6,还管理鼠标操作。

7,它还提供一个复杂的会话管理。它使程序在用户退出时可以“优美”的结束,或者如果干掉一个进程如果这个进程不能保留程序之前的状态(对会话管理不了解,翻译的不准确)

由于QApplication对象做了这么多初始化操作,所以它必须在所以与用户接口有关的对象创建之前被创建。

QCoreApplication类exec()方法分析

看看这个类是怎么调用线程那些东西的。
在QtCoreApplication类的exec()方法:

if (!QCoreApplicationPrivate::checkInstance("exec"))
        return -1;

    QThreadData *threadData = self->d_func()->threadData;
    if (threadData != QThreadData::current()) {
        qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
        return -1;
    }
    if (!threadData->eventLoops.isEmpty()) {
        qWarning("QCoreApplication::exec: The event loop is already running");
        return -1;
    }

    threadData->quitNow = false;
    QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();
    threadData->quitNow = false;
    if (self) {
        self->d_func()->in_exec = false;
        if (!self->d_func()->aboutToQuitEmitted)
            emit self->aboutToQuit();
        self->d_func()->aboutToQuitEmitted = true;
        sendPostedEvents(0, QEvent::DeferredDelete);
    }

    return returnCode;

我重点想知道的是,d_func()函数如何得到QThreadData对象的,这个需要进入到QCoreApplicationPrivate类当中了。
发现了这样的定义:

#define Q_DECLARE_PRIVATE(Class) /
    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } /
    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } /
    friend class Class##Private;

原来该类调用了qGetPtrHelper方法,继续跟踪下去:

template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }

其实d_func()是将QObjectData类的指针转换为QCoreApplicatPrivate类的指针。看下继承关系,QCoreApplicatPrivate继承自QObjectPrivate,QObjectPrivate继承自QObjectData;但是这样的转换还是会带来危险,因为本来这个指针就不是该类的,这样相当于扩大了对象的引用内存的大小,容易产生越界错误。而且这样的强转之后,也只是调用了其中来自 QObjectData的方法,这里的用意不是很明白,应该在其他地方对应用指针做了新的赋值。去找找看。
QScopedPointer d_ptr的定义来自QObject,现在找找看,是否有对该指针的赋值:
QObject::QObject(QObject *parent): d_ptr(new QObjectPrivate)
实际的引用对象就是QObjectPrivate类的对象了。
现在就可以总结一下了,整个Qt控制台应用程序框架基本明了:
我们编写的代码是:

QCoreApplication a(argc,argv);
a.exec();

通过这两行代码,Qt为我们做了如下工作:
首先创建一个用于保存整个程序运行核心数据的类对象:
QCoreApplication继承自QObject,所以,首先构造QOjbect类对象,于是有了:
D_ptr(new QObjectPrivate)
随后对QThread进行初始化:

#ifndef QT_NO_THREAD
    QThread::initialize();
#endif

接下来创建事件派送器,从Windows中将消息传递至Qt,并进行分发,构造函数完成。
随后调用a.exec()方法,获取线程信息:
QThreadData *threadData = self->d_func()->threadData;
最后进入事件循环,并进行事件发送等

对exec()函数的后半部分进行分析:

QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();
    threadData->quitNow = false;
    if (self) {
        self->d_func()->in_exec = false;
        if (!self->d_func()->aboutToQuitEmitted)
            emit self->aboutToQuit();
        self->d_func()->aboutToQuitEmitted = true;
        sendPostedEvents(0, QEvent::DeferredDelete);
    }

该方法在程序退出之前是不返回的,eventLoop.exec()的调用会让程序进入一个事件循环,直到程序结束。
进入QEventLoop中的exec方法:

Q_D(QEventLoop);
    if (d->threadData->quitNow)
        return -1;

    if (d->inExec) {
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
        return -1;
    }
    d->inExec = true;
    d->exit = false;
    ++d->threadData->loopLevel;
    d->threadData->eventLoops.push(this);
首先将事件类对象压入线程结构体中。
// remove posted quit events when entering a new event loop
    QCoreApplication *app = QCoreApplication::instance();
    if (app && app->thread() == thread())
        QCoreApplication::removePostedEvents(app, QEvent::Quit);

英文的注释说的已经很清楚了。

#if defined(QT_NO_EXCEPTIONS)
    while (!d->exit)
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
#else
    try {
        while (!d->exit)
            processEvents(flags | WaitForMoreEvents | EventLoopExec);
    } catch (...) {
        qWarning("Qt has caught an exception thrown from an event handler. Throwing/n"
                 "exceptions from an event handler is not supported in Qt. You must/n"
                 "reimplement QApplication::notify() and catch all exceptions there./n");

        // copied from below
        QEventLoop *eventLoop = d->threadData->eventLoops.pop();
        Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
        Q_UNUSED(eventLoop); // --release warning
        d->inExec = false;
        --d->threadData->loopLevel;

        throw;
    }
#endif

在此调用事件循环不同平台下的事件分派器的processEvent方法进行事件分析。
当出现异常时,将当前事件放弃掉。

// copied above
    QEventLoop *eventLoop = d->threadData->eventLoops.pop();
    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
    Q_UNUSED(eventLoop); // --release warning
    d->inExec = false;
    --d->threadData->loopLevel;

    return d->returnCode;

在此,事件循环退出。

qcoreapplication 与qapplication的联系与区别

故事的背景是这样的,我们在写QT程序的时候或者在开始写QT程序之前总会看到这样的语句

QApplication app(argc, argv);
这是什么呢? QApplication这个类是继承QCoreApplication的,而QCoreApplication有继承

QObject的,而QObject就是QT中最基本的基类,也就是QT的根基了,这里就从QCoreApplication

说起吧,头文件中有这样的开始

classQ_CORE_EXPORTQCoreApplication : public QObject
Q_CORE_EXPORT是什么呢?如果在编写动态库时,定义DLL符号,Q_GUI_EXPORT就是导出函数或者类了,如果在应用程序中使用时,不定义Dll符号,Q_GUI_EXPORT就是导入类或者函数了,这里当然是导入了,我们写的可是命令行的,不是编写动态库,下面就是一些函数和变量的定义了,看到这里我震惊了

QCoreApplication * instance ()
定义一个指向自己的实例,啊?这是要闹哪样啊?难道要调用自己不成,实现就在类内,因为是静态的static QCoreApplication *instance() { returnself; }就是返回一个 self

static QCoreApplication *self;
是一个私有的静态成员变量,实现在类外

QCoreApplication *QCoreApplication::self = 0;
这下算是知道这个 self是做什么的了,可是这里有个疑问,连QCoreApplication自己都没被创建呢,哪来的指向 QCoreApplication的指针存在呢?这里个人的解释是静态成员的创建应该类创建之前就已经存在了,至于这个指向暂且就不考虑了,或许系统会解决这个问题吧,这里就当成是一个指针吧。

这里有必要看一下这个QCoreApplication类的构造函数

QCoreApplication::QCoreApplication(int &argc, char **argv)     : QObject(*new QCoreApplicationPrivate(argc, argv)) 
{     
    init();
    QCoreApplicationPrivate::eventDispatcher->startingUp(); 
    #if defined(Q_OS_SYMBIAN) && !defined(QT_NO_LIBRARY)// Refresh factoryloader, as text codecs are requested during lib path// resolving process and won't be therefore properly loaded.// Unknown if this is symbian specific issue.     
    QFactoryLoader::refreshAll(); 
    #endif#if defined(Q_OS_SYMBIAN) &&!defined(QT_NO_SYSTEMLOCALE)     
    d_func()->symbianInit(); 
#endif 
}

下面看着有点晕了,这里就只看 init();这个函数,就在构造函数的下面,这里的代码更多了,

这里只写我们关注的一行

voidQCoreApplication::init(){ QCoreApplication::self = this;}
这里对 self进行了赋值,这就让这个self指向了当前这个对象,而不是什么也不指了,这个self就可以代替当前对象来使用了,当然这只能在类内,因为self是私有的,要在类外使用是不是应该定义一个共有成员函数什么的,先把疑问留在这里。

说完这个静态成员变量self还是没有解决这里为什么要闹这样的问题,原来我们在类定义的上一行看到这样的代码

#define qApp QCoreApplication::instance()

定义了一个 qApp宏,这个宏也就成了一个指针,指向的是自己,这样做又有什么用呢

当我们在主程序中定义了 QCoreApplication app(argc, argv);对象的时候完全是不需要用qApp这个宏的啊,但是如果出了主函数要用这个对象怎么办,传吗?这样比较麻烦,QT用这个指向自己的东东就是帮助我们解决这样要在主函数外使用app这个对象的而找不到对象的苦恼。好了,在函数外你就用qApp吧,这样会不会有什么问题呢?这个东西在内存吗?嘿嘿,这是静态的啊,就在内存呆着呢,大胆的去用这个指向自己的宏指针吧,只要app没析构这东东就一直在内存。

下面来说明一下QApplication,这个是从 QCoreApplication继承来的,

#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))

在类定义前有一段这样的代码,这里也是取 self这个指向自己的指针但是要做一个类型转换,至于这个类型转换是否安全,我想应该是安全的,因为相当于是从基类往派生类转换,基类有的应该是对拷贝的,但是这里的static会不会对这个造成困扰还不是很清楚,总之,要转换后这个qApp才能在主函数外使用。

这里还要说明的是这个 QCoreApplication是不是单例的问题,网上有很多人认为是单例,也有很多人赞成,但是我实践了一下应该不是单例

for(int i = 0 ; i < 3 ; ++i) 
{    
     QCoreApplication app;
  }

这里这样的操作时允许的,因为之前的已经析构了,QT中说的只允许创建一个是指在一个函数内,只能创建一个,这里显然不是,单例的实现一般都是通过私有构造函数来实现的,这里的构造函数是共有的显然不是单例的节奏。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QApplication与QCoreApplication 的相关文章

  • Qt 和 Google 地球 API

    是否可以使用 Google Earth 在 Qt 中开发应用程序 例如 我想在我的应用程序中通过 QtGL 将地球 如谷歌地球 显示为球体 很明显 您可以在 Qt 中使用 google Earth api 我想分享一个秘密 Google E
  • QTableView 仅显示使用 QAbstractItemModel 实现的树模型的叶子

    假设我有一个树结构 树叶在bold 抱歉这些点 A A1 A2 B B1 B11 B2 C 存储在 QAbstractItemModel 中 具有设置的父 子关系 如何在 QTableView 中仅显示树叶 基本思想是实现一个 QSortF
  • Qml中的QScrollArea:Flickable + QQuickPaintedItem

    我正在尝试实现类似的东西QScrollArea 在小部件世界中 在 Qml 的帮助下 我决定一探究竟Flickable plus QQuickPaintedItem基于项目 在我的例子中名为抽屉 Flickable onContentXCh
  • Qt - 如何将数据与 QTableWidgetItem 关联?

    我想将附加数据与插入表中的每个 QTableWidgetItem 相关联 以便将来在单击表项时使用该数据 但这些数据不应该是可见的 我怎样才能做到这一点 您可以使用QTableWidgetItem setData http doc qt i
  • Qt 样式表:无法使用 ID 选择器

    我正在学习使用 Qt 样式表向我的应用程序添加不同的样式 我在网上查看了 Qt 文档 其中说你可以使用名为ID Selector可以将主题应用于某些对象 这就是我实现此功能的方式 QPushButton button color red 但
  • Qt 5 和 OS X Mavericks 问题

    我正在使用 Cmake 在 OS X 10 9 上构建 QT 项目 自 Mavericks 以来 OpenGL 标头的位置似乎发生了变化 文件夹 System Library Frameworks OpenGL framework Head
  • 如何在 Qt 中实现 QHoverEvent?

    我正在学习 Qt 和 C 我已经成功地实现了信号和槽来捕获标准事件 例如ButtonPushed 等等 但是 我希望当我将鼠标悬停在鼠标上并移出鼠标时调用一个函数QLabel 看起来像QHover事件 http doc qt io qt 4
  • Qt Ui 命名空间

    命名空间有什么意义Ui这是Qt自动生成的吗 这两个命名空间相同吗 在第一个中 其中包含 MainWindow 类的前向声明ui MainWindow h为什么它没有声明为class Ui MainWindow 编译器如何知道 MainWin
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • 如何在使用 QSS 悬停父 QFrame 时设置子 QLabels 的颜色?

    我试图使用样式表设置 QFrame 内 2 个标签的悬停状态颜色 但无论是否存在实际悬停 框架都会采用悬停状态 See screenshot 我有一个带有 QLabels 的 QFrame 我将默认颜色设置为绿色和紫色 当我将鼠标悬停在 Q
  • 在 Mac 上启动没有停靠图标的 Qt 托盘进程

    我有一个包含 GUI 服务和托盘的捆绑包 请注意 它们是三个独立的过程 这可能听起来很奇怪 托盘是服务的代表 用户可以打开 GUI 如果没有托盘存在 它会创建一个托盘 所以在我的 GUI 代码中我有如下内容 QProcess startDe
  • QT:隐藏对话框/窗口的标题栏

    我有一个父窗口 其中按钮的单击事件函数具有以下几行 SplashScreenDialog splScrDlg new SplashScreenDialog this splScrDlg gt show 我想要的是我想从对话框 或窗口 中删除
  • QtWebKit 无需安装 flash 播放器即可播放 HTML5 视频

    安装最新的 Flash 播放器并启用插件后 我的简单示例可以播放 YouTube 视频 操作系统 Windows 7 Qt 4 7 4 32 位和 64 位均可 但是 根据 http www youtube com html5 我的示例浏览
  • 为什么我的自定义图形项目在基于 Qt 的 C++ GUI 应用程序中不断重新绘制?

    我的应用程序有一个 QMdiArea 其中显示子窗口 其中包含 QGraphicsView 派生视图 GfxInteractiveView 的实例 这些视图又可视化包含自定义 QGraphicsItem 派生项目的场景 An image i
  • 如何为列表中的每个元素创建一个按钮并将其放在滚动区域中?

    我有一个列表 每次用户打开文件时都会获取一个元素 我需要创建一个带有文件名 列表中的元素 的按钮 每次将该文件附加到列表中时 并将该按钮放入滚动区域 问题是我总是只有一个按钮 只是更改了名称 filenames def addfiles f
  • 如何将项目添加到布局中的特定索引

    我按照这个示例创建一个流布局 http doc qt io qt 4 8 qt layouts flowlayout example html http doc qt io qt 4 8 qt layouts flowlayout exam
  • 如何在 Qt 5 中写入和读取 QResource 文件?

    很奇怪 我通过以下方式将所需的文件添加到资源中添加现有文件 文件就在那里 我运行 qmake 构建 gt 运行 qmake 以使文件可用 第一期 我无法从输出终端向文件写入任何内容 但是当我手动写入文件时 每次运行它时输出终端都会显示更改
  • 创建 QT 应用程序作为 Windows 上现有基于控制台的应用程序的 GUI

    我正在尝试使用 Qt 为现有应用程序设置一个 GUI 该应用程序旨在在 Windows 命令行中运行 这不仅仅是运行应用程序system 命令 但我需要通过命令行与现有应用程序交互 The system 当我启动现有的可执行文件时 命令会阻
  • PyQt5:如何将 QPushButton 连接到插槽?

    好吧 几乎所有教程 可理解的用人类语言编写的文档都是针对 PyQt4 的 但是 PyQt5 改变了整个 将按钮连接到插槽 的工作方式 但我仍然不知道如何做到这一点 我在 QtDesigner 中做了一个快速 gui 并且有一个 QPushB
  • QGeoCoordinate:没有这样的文件或目录

    我正在尝试使用 QtLocation 但不能 我不明白为什么 我在 ubuntu 14 04 上使用 qt5 3 2 这很奇怪 因为我将这一行添加到我的 pro 文件中 QT network CONFIG mobility MOBILITY

随机推荐

  • PCL读取显示点云的两种方式

    读取点云的两种方式 PCL提供了两种pcd点云读写方式 其中PCD Point Cloud Date 点云数据 对应的文件格式为 pcd 是 PCL官方指定格式 具有 ASCII 和 Binary 两种数据存储类型 其中 ASCII 格式的
  • snipaste便捷截图小工具

    Snipaste是一个简单但强大的截图工具 也可以让你将截图贴回到屏幕上 下载并打开Snipaste 按下F1来开始截图 再按F3 截图就在桌面置顶显示了 还可以将剪贴板里的文字或者颜色信息转化为图片窗口 并且将它们进行缩放 旋转 翻转 设
  • 原码 反码 补码 移码

    原码 反码 补码都是有符号定点数的表示方法 一个有符号定点数的最高位为符号位 0是正 1是负 反码 原码 除符号位外 每位取反 补码 反码 1 反码 补码 1 移码 补码符号位取反 原码就是这个数本身的二进制形式 正数的反码和补码都是和原码
  • cmake错误:“未定义的引用”,“未声明的引用”

    描述 在编译代码的时候 经常会出现 未声明的引用 和 未定义的引用 之类的错误 原因 这种情况一般在编译的过程是不会出现问题 在链接的过程会出现这些问题 未声明的引用一般是头文件引入错误 或者找不到头文件 未定义的引用应该是找不到函数的实现
  • omv5-gitlab/gitlab-ce deploy

    omv5 gitlab gitlab ce yml example version 3 6 services web image gitlab gitlab ce latest restart always environment GITL
  • AWS架构图更新2019 - 最强大的AWS架构设计工具

    需要设计您的Amazon Web Services AWS 架构 今天我想介绍一下如何使用Visual Paradigm的云架构设计软件绘制AWS架构图快速而有趣 他们提供世界上最简单 最强大的AWS架构设计工具 全套AWS符号 创建专业的
  • Python-装饰器详解

    装饰器 介绍 在Python中 装饰器是一种特殊的语法 用于修改或增强函数的功能 装饰器是Python的高级特性之一 它允许我们通过在不修改原函数代码的情况下 添加额外的功能或行为 装饰器是一个函数 它接受一个函数作为参数 并返回一个新的函
  • 构建工具Maven/Gradle

    Maven Maven项目对象模型 POM 可以通过一小段描述信息来管理项目的构建 报告和文档的项目管理工具软件 Maven 除了以程序构建能力为特色之外 还提供高级项目管理工具 由于 Maven 的缺省构建规则有较高的可重用性 所以常常用
  • 微信小程序之微信登录

    在开发微信小程序的时候 我们经常需要用到微信登录 通过wx的接口来获取微信用户的信息 然后存储到我们数据库来创建属于我们系统的用户信息 所以我们就要使用到wx login wx getUserProfile 这两个方法 wx login w
  • 向量点乘叉乘等理解和应用

    https baike baidu com item E5 90 91 E9 87 8F 1396519 fr aladdin 1 标量和矢量 2 1 2 3 2 4 6 2 4 6 2 1 2 3 2 矢量和矢量的加减 三角形定则解决向量
  • 程序员3年5年10年三个阶段

    第一阶段 三年 三年对于程序员来说是第一个门槛 这个阶段将会淘汰掉一批不适合写代码的人 这一阶段 我们走出校园 迈入社会 成为一名程序员 正式从书本上的内容迈向真正的企业级开发 我们知道如何团队协作 如何使用项目管理工具 项目版本如何控制
  • 奇偶剪枝算法

    奇偶剪枝是数据结构的搜索中 剪枝的一种特殊小技巧 现假设起点为 sx sy 终点为 ex ey 给定t步恰好走到终点 如图所示 竖走 横走 转弯 易证abs ex sx abs ey sy 为此问题类中任意情况下 起点到终点的最短步数 记做
  • 弱网使用教程

    Network Emulation for Windows Toolkit 1 下载安装包 默认安装 下载地址 https drive google com file d 1jvviwEDRx2UtmpUxe1 Sy94E3wBao5Ot
  • 基于51单片机的红外解码器

    1 简介 本红外解码器是以MCS 51系列AT89C512片机为核心 将红外传感器接收的信号解析出来 LCD1602显示屏将解码数据显示出来 2 总体原理图 硬件组成 单片机最小系统 LCD1602显示屏 IR红外接收器 系统电源 3 程序
  • 数据结构---n皇后问题

    n皇后问题 题目描述 JAVA实现 力扣提交代码 n皇后问题 题目描述 对于四皇后问题的解 放置一个皇后 棋盘被占据的解为 很明显 每行只能放置 且只能放置一个皇后 代码中 queen row 1 来实现的 一个完整的示例 放第一个皇后 放
  • 抖音将会输给快手?时间会证明一切

    为什么快手产品的主界面上没有设置频道分类 这样带来的用户体验真的好吗 在快手一个月之前的员工大会上 入职不久的新员工赵波提出了这个疑问 这个问题不只是他一个人的 之前官方的解答是 不意给用户设置标签是为了保持界面简洁 不对内容做过多的评判
  • i.MX6ULL - 从零开始移植uboot-imx_v2020.04_5.4.70_2.3.0

    i MX6ULL 从零开始移植uboot imx v2020 04 5 4 70 2 3 0 目录 i MX6ULL 从零开始移植uboot imx v2020 04 5 4 70 2 3 0 前言 1 环境搭建 2 NXP官方原版UBOO
  • 一文解决VS Code安装、C++环境配置、OpenCV配置

    前言 本文包括VScode安装 C 环境配置以及OpenCV配置全过程 VS Studio配置OpenCV比较简单 可以直接使用OpenCV官网已有的用VS Studio编译器编译好的OpenCV库 但VS Code不能直接利用VS Stu
  • Android:基本程序单元 Activity

    Activity 概述 在 Android 应用中 提供了 4 大基本组件 分别是 Activity Service BroadcastReceiver 和 ContentProvider 而 Activity 是 Android 应用最常
  • QApplication与QCoreApplication

    QApplication GUI 程序中 有且仅有一个 QApplication 类 管理GUI程序的控制流和主设置 QApplication 包含主事件循环 所有来自窗口系统和其他源的事件将被处理和分配 它也处理程序的初始化 析构和提供会