Qt多线程与GUI

时间:2017-08-07 13:21:04

标签: c++ multithreading qt

我无法生成一个非常简单的示例来开始使用Qt多线程。我阅读了很多帖子和教程,但它仍然没有用。

目标

让后台工作者独立于GUI。哦,哇......

我做了什么

一个简单的例子:

  • 创建Engine
  • 显示QMainWindow
  • 并启动一个打印数字的QTimer

如果您左键单击GUI的标题栏,请按住鼠标按钮(即最小化按钮)计数器将停止!即使它是在非GUI环境中创建的,并且它已在另一个线程中移动了!

为什么?

的main.cpp

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Engine e;

    return a.exec();
}

engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QThread>
#include <QTimer>

#include "mainwindow.h"

class Engine : public QObject
{
    Q_OBJECT

public:
    explicit Engine(QObject *parent = 0);

private:
    MainWindow mainWindow;
    QThread *thread;
    QTimer *timer;

private slots:
    void foo();

};

#endif // ENGINE_H

engine.c

#include "engine.h"
#include <QDebug>

Engine::Engine(QObject *parent) : QObject(parent)
{

    thread = new QThread(this);
    timer = new QTimer();
    timer->setInterval(100);
    connect(timer, &QTimer::timeout, this, &Engine::foo);
    connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
    timer->moveToThread(thread);
    thread->start();

    mainWindow.show();
}

void Engine::foo()
{
    static int i;
    qDebug() << ++i;
}

QMainWindow不包含任何代码。

2 个答案:

答案 0 :(得分:5)

基本上,Qt有一个处理GUI的线程(通常是主线程)。 GUI工作将阻止特定于此线程的任何对象。您需要将GUI保留在交互式合作伙伴之外。

更具体地说,您的Engine对象驻留在GUI /主线程中。即使您的计时器被发送到工作线程,它的信号也会被分派到主线程中的插槽foo()

您需要对Engine和主窗口进行解除处理,使Engine可以驻留在自己的线程中,并在GUI阻塞时处理信号。

答案 1 :(得分:1)

看起来您将QTimer实例移动到了自定义线程,但是您没有将Engine实例移动到此线程,因此,Engine类的foo槽将在主线程中执行。

我建议您在Engine类中使用额外帮助QObject派生的类实例,并将其移动到Engine构造函数中的新线程。

使用以下更改解决方案即使按下最小化按钮也能正常工作(我已经评论了我添加或更改任何内容的位置。还添加了新的QObject派生类 EngineWorker ):

Engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QThread>
#include <QTimer>

#include "mainwindow.h"
#include "engineworker.h"

class Engine : public QObject
{
    Q_OBJECT

public:
    explicit Engine(QObject *parent = 0);

private:
    MainWindow mainWindow;
    QThread *thread;
    QTimer *timer;

    //additional QObject-derived class
    EngineWorker *worker;

private slots:
    void foo();

};

#endif // ENGINE_H

Engine.cpp

#include "engine.h"
#include <QDebug>


Engine::Engine(QObject *parent) : QObject(parent)
{
      thread = new QThread(this);
      timer = new QTimer();

      //Creating instance of Engine worker
      worker = new EngineWorker();

      timer->setInterval(100);

      //Connecting Engine worker' foo slot to timer
      connect(timer, &QTimer::timeout, worker, &EngineWorker::foo);
      connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
      timer->moveToThread(thread);
      //Moving worker to custom thread
      worker->moveToThread(thread);

      thread->start();

      mainWindow.show();
}

void Engine::foo()
{
    static int i;
    qDebug() << ++i;
}

EngineWorker.h

#ifndef ENGINEWORKER_H
#define ENGINEWORKER_H

#include <QObject>
#include <QDebug>

class EngineWorker : public QObject
{
    Q_OBJECT
public:
    explicit EngineWorker(QObject *parent = 0);

signals:

public slots:
    void foo();
};

#endif // ENGINEWORKER_H

EngineWorker.cpp

#include "engineworker.h"

EngineWorker::EngineWorker(QObject *parent) : QObject(parent)
{

}

//foo slot of EngineWorker class
void EngineWorker::foo()
{
    static int j;
    qDebug() <<"Worker: "<< ++j;
}
相关问题