在不同的线程中创建 QApplication

Posted

技术标签:

【中文标题】在不同的线程中创建 QApplication【英文标题】:creating QApplication in a different thread 【发布时间】:2014-08-17 12:14:44 【问题描述】:

我正在尝试,但发现了 2 个主要问题: 1- 我无法与 GUI 交互 2- 一些警告:WARNING: QApplication was not created in the main() thread. QObject::startTimer: timers cannot be started from another thread //happens when resizing widget QObject::killTimer: timers cannot be stopped from another thread

这是完整的代码:(它可能有一些内存泄漏,但出于测试目的它失败了)

//main.cpp

#include <QCoreApplication>
#include "cthread.h"

int main(int argc, char *argv[])

    CThread *MyThread = new CThread;
    MyThread->start();

    QCoreApplication a(argc, argv);

    return a.exec();

//CThread.h

#ifndef CTHREAD_H
#define CTHREAD_H

#include <QThread>
#include "theqtworld.h"

class CThread : public QThread

    Q_OBJECT
public:
    CThread();
    void run( void );

private:
    TheQtWorld *mWorld;
;

#endif // CTHREAD_H

//CThread.cpp

#include "cthread.h"
#include <iostream>

CThread::CThread():mWorld(NULL)




void CThread::run()

    std::cout << "thread started" << std::endl;
    if(!mWorld)
        mWorld = new TheQtWorld();

    mWorld->OpenWorld();//now it will init all Qt Stuff inside

//    if(mWorld) delete mWorld;
//    emit this->exit();

//theqtworld.h

#ifndef THEQTWORLD_H
#define THEQTWORLD_H

#include <QObject>
#include "mainwindow.h"
#include <QApplication>

class TheQtWorld : public QObject

    Q_OBJECT
public:
    explicit TheQtWorld(QObject *parent = 0);
    int OpenWorld(void);

signals:

public slots:

;

#endif // THEQTWORLD_H

//theqtworld.cpp

#include "theqtworld.h"

TheQtWorld::TheQtWorld(QObject *parent) :
    QObject(parent)



int TheQtWorld::OpenWorld()

    static int arg = 0;
    static char *b[2];
    b[0] = "a";

    QApplication *a = new QApplication(arg, b);
    a->setParent(this);

    MainWindow w;
    w.show();

    return a->exec();

【问题讨论】:

为什么要在另一个线程中创建应用程序?我看不出有任何理由这样做,而且我很确定 Qt 不支持它。 整个工作流程将是另一个非 Qt 应用程序的插件,它有自己的事件系统,所以我不能在主线程中放置阻塞调用 有解决此问题的方法。定期调用QApplication::processEvents() 而不是调用QApplication::exec 可能会有所帮助。谷歌“qt 在另一个事件循环中集成”。另请参阅this。 @MohamedSakrAboYoucuf,您可以简单地使用 QThread!每个 QThread 都有不同的事件循环。您不需要新的 Q*Application 实例(Qt 不支持)来拥有新的 eventLopp 我在 main() 函数中有一个 QCoreApplication。仅允许使用 1 个 QCoreApplication 或其派生的实例(我使用 Q*Application 表示法)。 @MohamedSakrAboYoucuf 阅读 here 以了解如何使用 QThread 使用不同的 eventLoop 【参考方案1】:

在了解如何克服这个问题后,我会回答我自己的问题

首先问题是将 Qt GUI 作为插件集成到另一个应用程序中,因此主要问题是 Qt 事件与任何其他应用程序事件之间的事件循环冲突

我的第一个想法是将两者分开,因此 QApplication 将留在不同的线程,但这是一种完全错误的方法,这是我注意到的:

1- Qt GUI 必须留在 main() 线程so there is no other place for QApplication 2-为了避免阻塞 QApplication::exec() ,将 QApplication::processEvents() 嵌入到另一个应用程序事件循环中

这是一个工作代码:

//main.cpp

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])

    QApplication mApp(argc, argv);
    MainWindow w;
    w.show();

    //just for testing and holding the program so it doesn't end
    for(int i = 0; i < 100000000; ++i)
    
        mApp.processEvents();
    
    return 0;

edit:感谢 pavel-strakhov 的出色建议。

【讨论】:

这不会消耗 100% cpu 吗? 对于这个测试“这么大的for循环,processEvents()之间没有间隔”是的,它会让CPU保持忙碌,但是一旦你设置了间隔并美化了代码,你就可以在for中做其他事情loop "例如你可以做其他计算,这个for循环只是另一个应用程序的事件循环的表示" 如果主线程不可用,您有什么建议吗?我正在尝试将一些 GUI 调试窗口嵌入到非 qt 应用程序中。我尝试调试的应用程序部分不在主线程中运行。 @TomášZato 没关系,您需要从正在运行的线程中调用您的 Qt 应用程序,并使用 mApp.processEvents() 从那里进行控制;如上例

以上是关于在不同的线程中创建 QApplication的主要内容,如果未能解决你的问题,请参考以下文章

主线程中创建不同的handler实例,接收消息会不会冲突

如何使用 C++ 在 Windows 中创建守护线程?

在 Spring Cloud GCP pubsub 中创建特定于消息通道的线程

如何在 Spring Boot 中创建不同的 ThreadPoolTask​​Executor? [复制]

转:MFC中创建多线程

在 CoreData 的后台线程中创建实体