Qt源码分析:Qt程序是怎么运行起来的?

2024-01-09

一、从 exec() 谈起

一个标准的Qt-gui程序,在启动时我们会coding如下几行简洁的代码:

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

在这里我们首先考虑第一个问题,如果主程序中没有调用 a.exec() ,在编译运行时会发生什么?
~~ one thousand years later~~
对,也许你已经非常清楚了,你定义的 widget 窗口竟然没有显示,或者你以自己如同高速摄像机的神器双眼,炯炯侠般捕获到窗口突然的闪现然后消失。这时候你明白, a.exec() 是保证窗口程序不立即退出的重要保证。
你的猜想很对,同时我要告诉你的是, a.exec() 做的工作显然比这要多很多。

二、源码分析

    QObject
		|__QCoreApplication					   源码路径:qtbase\src\corelib\kernel\qcoreapplication.cpp
					|__QGuiApplication            源码路径:qtbase\src\gui\kernel\qguiapplication.cpp
								|_QApplication       源码路径: qtbase\src\widgets\kernel\qapplication.cpp

		        图2.1   QApplication 继承类图

我们采用源码调试的方式,倒推来看我们的关注点。

1、 QApplication a(argc, argv);

对象实例化,构造函数如下:

#ifdef Q_QDOC
QApplication::QApplication(int &argc, char **argv)
#else
QApplication::QApplication(int &argc, char **argv, int _internal)
#endif
    : QGuiApplication(*new QApplicationPrivate(argc, argv, _internal))
{
    Q_D(QApplication);
    d->init();	/// 资源初始化
}

2、 a.exec()

int QCoreApplication::exec()
{
	// [1]
    if (!QCoreApplicationPrivate::checkInstance("exec"))
        return -1;

	// [2]
    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;
    }
	// [3]
    if (!threadData->eventLoops.isEmpty()) {
        qWarning("QCoreApplication::exec: The event loop is already running");
        return -1;
    }

	// [4]
    threadData->quitNow = false;
    QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();
    threadData->quitNow = false;

	// [5]
    if (self)
        self->d_func()->execCleanup();

    return returnCode;
}

下面掰开了,揉碎了,逐行扒光了解读一番:


[1]

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

判断 QCoreApplication 对象是否已经实例化,否则打印输出错误信息并退出。

bool QCoreApplicationPrivate::checkInstance(const char *function)
{
    bool b = (QCoreApplication::self != nullptr);
    if (!b)
        qWarning("QApplication::%s: Please instantiate the QApplication object first", function);
    return b;
}

[2]


 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;
    }

self->d_func() ,有点眼熟啊,这不就是Qt的孪生指针刺客 : q 指针和 d 指针 中 d 指针么?对这一块内容和知识不太熟悉的朋友,回头去看看博主曾经写过的相关内容 《Qt : d指针和q指针?》

我们回过头看看 QCoreApplication 是如何申明的:

class Q_CORE_EXPORT QCoreApplication
#ifndef QT_NO_QOBJECT
    : public QObject
#endif
{
 Q_DECLARE_PRIVATE(QCoreApplication)
 protected:
    QCoreApplication(QCoreApplicationPrivate &p);
	// ...
#ifdef QT_NO_QOBJECT
    QScopedPointer<QCoreApplicationPrivate> d_ptr;
#endif

// ...
}
#define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \
    friend class Class##Private;

ok,读到这儿,我们先收起更深的好奇之心,我们拿到了我们暂时需要知道的, self->d_func() 获取到了 QCoreApplicationPrivate 的成员变量指针,即 QScopedPointer<QCoreApplicationPrivate> d_ptr;

class Q_CORE_EXPORT QCoreApplicationPrivate
#ifndef QT_NO_QOBJECT
    : public QObjectPrivate
#endif
{
 // ...
};
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
public:
	// ....
    ExtraData *extraData;    // extra data set by the user
    QThreadData *threadData; // id of the thread that owns the object
};

喔嚯.回过头来再看这一段.

  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;
    }

这是是干啥啊,获取当前对象所在线程的id,哪个对象? QCoreApplication 对象或者它的子类对象 QApplication a; 并判断当前线程id与对象所在线程id是否相同,不同则会给出错误提示并退出。

所以,这里有个知识点我们必须记住: QCoreApplication 及其子类,仅且只能在主线程中实例化!!!


[3]

我们先熟悉下 QThreadData 类

class QThreadData
{
public:
    QThreadData(int initialRefCount = 1);
    ~QThreadData();

    static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true);
#ifdef Q_OS_WINRT
    static void setMainThread();
#endif
    static void clearCurrentThreadData();
    static QThreadData *get2(QThread *thread)
    { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; }


    void ref();
    void deref();
    inline bool hasEventDispatcher() const
    { return eventDispatcher.loadRelaxed() != nullptr; }
    QAbstractEventDispatcher *createEventDispatcher();
    QAbstractEventDispatcher *ensureEventDispatcher()
    {
        QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed();
        if (Q_LIKELY(ed))
            return ed;
        return createEventDispatcher();
    }

    bool canWaitLocked()
    {
        QMutexLocker locker(&postEventList.mutex);
        return canWait;
    }

    // This class provides per-thread (by way of being a QThreadData
    // member) storage for qFlagLocation()
    class FlaggedDebugSignatures
    {
        static const uint Count = 2;

        uint idx;
        const char* locations[Count];

    public:
        FlaggedDebugSignatures() : idx(0)
        { std::fill_n(locations, Count, static_cast<char*>(nullptr)); }

        void store(const char* method)
        { locations[idx++ % Count] = method; }

        bool contains(const char *method) const
        { return std::find(locations, locations + Count, method) != locations + Count; }
    };

private:
    QAtomicInt _ref;

public:
    int loopLevel;
    int scopeLevel;

    QStack<QEventLoop *> eventLoops;    事件循环的主角来了
    QPostEventList postEventList;
    QAtomicPointer<QThread> thread;
    QAtomicPointer<void> threadId;
    QAtomicPointer<QAbstractEventDispatcher> eventDispatcher;
    QVector<void *> tls;
    FlaggedDebugSignatures flaggedSignatures;

    bool quitNow;
    bool canWait;
    bool isAdopted;
    bool requiresCoreApplication;
};

QStack<QEventLoop *> eventLoops; QThreadData 类 中的一个成员变量,它是一个栈,用于存储 QEventLoop 对象的指针。

Qt 中,每个 QThread 都有一个与之关联的事件循环(QEventLoop)。事件循环是 GUI 程序的核心,它用于接收和处理各种事件,如用户输入、定时器事件、网络事件等。

然而,一个线程不仅可以有一个主事件循环,还可以有一个或多个嵌套的事件循环。例如,当你在一个线程中调用 QEventLoop::exec() 时,你就创建了一个新的事件循环,并将其推入到 eventLoops 栈中。当 QEventLoop::exit() 被调用时,当前的事件循环会结束,并从 eventLoops 栈中弹出。

eventLoops 栈的顶部始终是当前线程的当前事件循环。这意味着,当你在一个线程中调用 QCoreApplication::processEvents() 时,Qt 会处理 eventLoops 栈顶的事件循环中的事件。

总的来说, QStack<QEventLoop *> eventLoops 成员变量用于存储和管理一个线程中的所有事件循环。

if (!threadData->eventLoops.isEmpty()) {
        qWarning("QCoreApplication::exec: The event loop is already running");
        return -1;
    }

这段,如果栈容器中的事件数量为空,则说明 QCoreApplication 事件循环还没有运行,否则,说明已经入事件循环状态。如果没有进入,那么继续往下走。


	/// 将几个标识状态对应初始化 
	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()->execCleanup();
int QEventLoop::exec(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    //we need to protect from race condition with QThread::exit
    QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread.loadAcquire()))->mutex);
    if (d->threadData->quitNow) // 已经设置为false
        return -1;

    if (d->inExec) {  // 已经设置为true
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
        return -1;
    }

    struct LoopReference {
        QEventLoopPrivate *d;
        QMutexLocker &locker;

        bool exceptionCaught;
        LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
        {
            d->inExec = true;
            d->exit.storeRelease(false);
            ++d->threadData->loopLevel;   /// 线程等级提升+1
            d->threadData->eventLoops.push(d->q_func()); /// 事件入栈
            locker.unlock();
        }

        ~LoopReference()
        {
            if (exceptionCaught) {
                qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
                         "exceptions from an event handler is not supported in Qt.\n"
                         "You must not let any exception whatsoever propagate through Qt code.\n"
                         "If that is not possible, in Qt 5 you must at least reimplement\n"
                         "QCoreApplication::notify() and catch all exceptions there.\n");
            }
            locker.relock();
            QEventLoop *eventLoop = d->threadData->eventLoops.pop();
            Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
            Q_UNUSED(eventLoop); // --release warning
            d->inExec = false;
            --d->threadData->loopLevel;
        }
    };
    LoopReference ref(d, locker);

    // remove posted quit events when entering a new event loop
    QCoreApplication *app = QCoreApplication::instance();
    if (app && app->thread() == thread())
        QCoreApplication::removePostedEvents(app, QEvent::Quit);

#ifdef Q_OS_WASM
    // Partial support for nested event loops: Make the runtime throw a JavaSrcript
    // exception, which returns control to the browser while preserving the C++ stack.
    // Event processing then continues as normal. The sleep call below never returns.
    // QTBUG-70185
    if (d->threadData->loopLevel > 1)
        emscripten_sleep(1);
#endif

	/**************************************************************************/
    while (!d->exit.loadAcquire())
        processEvents(flags | WaitForMoreEvents | EventLoopExec);  /// 加入到事件循环stack中
   /**************************************************************************/
    ref.exceptionCaught = false;
    return d->returnCode.loadRelaxed();
}

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

Qt源码分析:Qt程序是怎么运行起来的? 的相关文章

  • SWI-Prolog 与 C++ 接口的问题

    我试图让 SWI Prolog 与 C 很好地配合 现在束手无策 现在 在我开始准确解释我的问题是什么之前 我想首先说明我的项目是关于什么的以及我选择了哪些工具来开发解决方案 我的教授分配给我的任务是开发一个 GUI 程序 作为 SWI p
  • 我应该使用 QCoreApplication::processEvents() 还是 QApplication::processEvents()?

    我有一个从两者调用的方法QThreads和主线程 这个方法有时可能需要很长时间才能在循环中进行计算 所以我把QCoreApplication processEvents 这可以防止 GUI 冻结 在某个时刻我已经改变了QCoreApplic
  • 如何使 Python、QT 和 Webkit 在无头服务器上工作?

    我有 Debian Linux 服务器 我用它来做各种事情 我希望它能够完成一些我需要定期完成的网络抓取工作 这段代码可以是在这里找到 http bit ly QeqvzX import sys from PyQt4 QtGui impor
  • 打开和关闭附加窗口 (QML)

    目前我有一个通过以下方式打开的窗口 property variant win Button id testButton MouseArea onClicked var component Qt createComponent test qm
  • Qt5和QML:如何使用WebEngine Quick Nano浏览器自动输入用户名和密码

    我正在使用编写一个小应用程序Qt and QML使用 Qt 文档中的示例WebEngine Quick Nano 浏览器 https doc snapshots qt io qt5 5 9 qtwebengine webengine qui
  • Qml 和模糊图像

    我想使用 QML 实现模糊效果 我找到了有关 效果 模糊 的参考资料 例子 http qt gitorious org lscunha qt components lscunha qt components blobs d78feec567
  • 在 Qt 服务器上验证用户身份

    我正在尝试使用 C QtTcpSocket 为个人项目 多人国际象棋游戏 实现身份验证系统 我的朋友建议了一种验证用户的方法 但我想问是否有更简单或更好的方法 来自 Python 背景 做这个项目主要是为了加深对 C 的理解 我将发布我朋友
  • QComboBox 下拉项边距

    我想设计我的风格QComboBox为下拉项目留出边距 现在是这样的 我想要这样的东西 我尝试过 QComboBox QAbstractItemView item margin 3px 但它不起作用 你能帮我解决这个问题吗 您想在项目之间设置
  • QMutex 是否需要是静态的,以便此类实例的其他线程调用知道暂停其操作?

    从多个线程调用以下附加函数 我不希望数据重写附加 因为计数器尚未增加 除了当前使用 Append 的线程之外 这是否会挂起所有进入的线程 或者其他线程会继续运行而不追加数据吗 互斥锁是否需要是 静态 的 或者每个实例都知道要暂停操作吗 如果
  • 获取 QListView 中所有可见项目的简单方法

    我正在尝试使用 Qt Framework 开发一个图像库应用程序 应用程序从所选文件夹加载所有图像 并使用 QListView 控件显示这些图像 但现在我想通过仅加载用户可见的图像来减少内存消耗 由于没有直接函数来获取视图中的所有可见项目
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • 如何在Qt 5中的paintEvent上使用mouseMoveEvent?

    我是 Qt 和 c 的新手 所以我遇到了一些困难 我正在尝试创建一个小部件 它可以获取 mouseMoveEvent 位置并在鼠标位置的像素图上绘制椭圆 下面你可以看到代码 include myimage h include
  • 如何在针对 Windows XP 的情况下使用 VS2012 构建 Qt 4/5?

    我正在尝试使用 Visual Studio 2012 构建 Qt 4 8 5 Qt 5 2 1 针对 Windows XP SDK v7 1a 使用 VS2102 编译时 源代码与 SDK v7 1a 存在各种不兼容性 因此无法开箱即用 这
  • 将 jstring 转换为 QString

    我正在调用一个返回字符串的 Java 函数 QAndroidJniObject obj QAndroidJniObject callStaticObjectMethod
  • QTableView 并双击一个单元格

    我正在开发测试用例编辑器 该编辑器包含 USART 传输和接收数据包格式 编辑器是一个表格视图 发送和接收数据包的长度为八个字节 例如 0x01 0x02 0x03 0x08 它在我的第五和第六栏中 现在 我希望此列中的单元格为只读 但是当
  • 是否有 Qt 小部件可以浏览应用程序中小部件的层次结构(类似于 Spy++)?

    我们有一个具有复杂的小部件层次结构的应用程序 我希望能够以与 Spy 类似的方式浏览此层次结构 查看和编辑属性 例如大小 如果有一个小部件可以显示此信息 则它不需要在外部应用程序中运行 那么问题来了 这样的神兽存在吗 您可以使用Gammar
  • 覆盖 QWebView 中的页面回复

    我试图在 Qt 的 QWebView 中拦截页面 表单请求 并在某些情况下使用替代内容进行响应 QNetworkReply ngcBrowser createRequest Operation operation const QNetwor
  • QFileSystemModel setRootPath

    我正在尝试创建一个 Qt 应用程序来显示文件夹 Mac OS 中的 Users 文件夹 的内容 这是代码 QFileSystemModel dirModel new QFileSystemModel dirModel gt setRootP
  • QTabWidget 选项卡在垂直方向,但文本在水平方向

    我正在尝试用 C Qt 制作一个带有这样的侧边栏的应用程序 但是当将 QTabWidget 方向设置为西时 它会使文本垂直 如何让文本位于左侧 但水平对齐 PS 我不需要图标 提前致谢 您可以使用QListWidget http doc q
  • Qt 支持 Windows 蓝牙 API 吗?

    谁能告诉我 Qt 是否支持 Windows 蓝牙 API 如果是这样 您能否分享一些有关如何使用它的信息 自上次答复以来 这个问题的答案发生了一些变化 Qt 5 2 版为 Linux BlueZ 和 BlackBerry 设备实现了蓝牙 A

随机推荐

  • rknn加载onnx时报错 GLIBC=2.29 no found librknnc.so

    rknn 中onnx转rknn在虚拟机中运行时发现报错 GLIBC 2 29 no found librknnc so 昨天还正常的 今天装了个ftp 和宝塔面板就出错了 我估计根据报错地址 找到了librknnc so文件 权限也给了77
  • Java毕业设计基于springboot企业车辆管理系统设计与实现

    一 项目介绍 随着时代在飞速进步 每个行业都在努力发展现在先进技术 通过这些先进的技术来提高自己的水平和优势 企业车辆管理系统当然不能排除在外 企业车辆管理系统是在实际应用和软件工程的开发原理之上 运用Java语言以及SpringBoot框
  • 全功能tgbot/Telegram机器人多功能有后台版源码

    全功能tgbot telegram机器人多功能有后台版源码 打包好的可以直接上手 trx兑换 闪兑 关键字监控 群管 usdt监控 余额查询 推广分享 等几乎常见的tg机器人功能都有
  • 期权怎么开户:期权开户免费吗,需要什么样的门槛?

    期权开户是免费的 只有交易才会产生费用 开通期权账户需要满足50万的资金 以及融资融券交易经验或者金融期货交易经验 当然也有免50万门槛的开户方式 下文为大家科普期权怎么开户啊 期权开户免费么 一般情况下 期权是可以通过在营业部网点进行开户
  • 深入浅出《Delta-Sigma Data Converters》(可下载)

    在数字信号处理领域 数据转换器是实现模拟与数字世界之间无缝转换的关键组件 而在这个子领域中 Delta Sigma Data Converter s 一书以其全面和深入的内容 为工程师 学者甚至爱好者们提供了一个极其宝贵的资源 今天将为大家
  • go cannot find package “github.com/gorilla/websocket“解读

    Go无法找到包 github com gorilla websocket 的解决方案 在Go开发过程中 我们经常会依赖第三方库来简化开发工作 而使用 go get 命令安装这些库时 有时候我们可能会遇到类似于以下错误的情况 plaintex
  • java.io.IOException: Broken pipe

    做1个接口 处理前端请求图片跨域的问题 由于前端拿图片的时候 有跨域问题 所以让后台先拿到图片 然后再写给前台 本来下面的代码没什么太大的问题 但是如果前台请求的图片一多 1个页面中有很多图片 有些请求就会报错 java io IOExce
  • 数据采集才是MES系统的核心内容

    一 数据采集在MES管理系统中的应用 1 设备数据采集 MES管理系统通过与生产设备的连接 可以实时采集设备运行状态 产量 质量等相关数据 这有助于企业及时掌握设备运行状况 优化设备资源配置 提高设备利用率 2 工艺数据采集 MES管理系统
  • Typecho 最新XC主题 去除域名授权全解密源码

    简介 Typecho 最新XC主题 去除域名授权全解密源码 这是一款多样式主题 首页支持六种主题样式 支持Pjax优化访问速度 多种单页 如友链 说说等 评论支持表情 自定义编辑器 支持其他样式功能 该主题功能性挺高 比较花里胡哨 感觉有一
  • Java毕业设计基于springboot汽车服务管理系统

    一 项目介绍 随着社会的发展 汽车服务的管理形势越来越严峻 越来越多的用户利用互联网获得信息 但汽车服务信息鱼龙混杂 信息真假难以辨别 为了方便用户更好的获得汽车服务信息 因此 设计一种安全高效的汽车服务管理系统极为重要 为设计一个安全便捷
  • 适用于任何公司的网络安全架构

    1 第一等级 基础级 优势 可防范基本有针对性的攻击 使攻击者难以在网络上推进 将生产环境与企业环境进行基本隔离 劣势 默认的企业网络应被视为潜在受损 普通员工的工作站以及管理员的工作站可能受到潜在威胁 因为它们在生产网络中具有基本和管理员
  • 【OCR】实战使用 - 如何提高识别文字的精准度?

    实战使用 如何提高文字识别的精准度 我们在平常使用OCR的时候 经常会出现文字识别不精准的情况 我们改如何提高文字识别的精度呢 以下是一些提高OCR Optical Character Recognition 光学字符识别 文字识别精准度的
  • CMAKE_MAKE_PROGRAM is not set 解读

    目录 CMAKE MAKE PROGRAM 未设置 错误原因 解决方案 示例1 GNU Make 示例2 Ninja CMakeLists txt 的结构 示例 CMakeLists txt 文件 总结 CMAKE MAKE PROGRAM
  • 【每日论文阅读】Do Perceptually Aligned Gradients Imply Robustness?

    近似人眼梯度 https icml cc virtual 2023 oral 25482 对抗性鲁棒分类器具有非鲁棒模型所没有的特征 感知对齐梯度 PAG 它们相对于 输入的梯度与人类的感知非常一致 一些研究已将 PAG 确定为稳健训练的副
  • 黑豹程序员-字符串中查找出重复的字符串

    Collections frequency codeList element 字符串element 在codeList集合中重复的次数 List
  • 字节码指令例子分析

    什么是字节码指令 字节码指令就是由一个字节长度的操作吗和操作数组成 有些只有操作码 没有操作数 例如 bipush 10 第一个参数就是操作码 第二个是操作数 a 和i 有什么区别 public static void main Strin
  • Linux搭建测试环境详细步骤

    本文讲解如何在Linux CentOS下部署Java Web项目的步骤 环境准备 1 Linux系统 2 JDK 3 Tomcat 4 MySQL 工具下载 一 Linux系统 本文主要是Linux CentOS7为例 自己在家练习小项目的
  • 浏览器缓存相关面试题一网打尽,理论结合实践,用代码学习缓存问题,建议关注+收藏,(含项目源代码)

    前言 浏览器缓存的问题是面试中关于浏览器知识的重要组成部分 也是性能优化题目的一部分 但是不要被吓到 我话放到这里 就那么点东西 我这一篇文章基本上就涵盖了所有相关的知识点 认真看一遍 所有的问题都是纸老虎 一 准备工作 1 1 拉取仓库
  • “单项突出”的赢双科技IPO加速,比亚迪是最强助力?

    近日 新能源汽车核心部件供应商赢双科技首次递表科创板 其凭借旋转变压器产品就坐稳了新能源车企主要供应商的地位 从核心业务及业绩情况来看 赢双科技不愧为 单项冠军 据悉 赢双科技本次IPO拟募资8 47亿元 主要将用于年产旋转变压器910万台
  • Qt源码分析:Qt程序是怎么运行起来的?

    一 从 exec 谈起 一个标准的Qt gui程序 在启动时我们会coding如下几行简洁的代码 include widget h include