Qt GUI用户与QThread对象内的QMessageBox交互

han*_*dle 2 user-interface qt multithreading

我正在使用QThread MyObject->moveToThread(myThread);来进行需要一段时间的通信功能.一些信号和插槽保持GUI发布有关进度.

但是,在需要用户交互的线程通信期间可能会出现某些情况 - 因为无法在线程内创建QMessageBox,我想发出一个信号,允许我暂停线程并显示对话框.但首先,似乎没有办法暂停一个线程,其次,这种尝试可能会失败,因为它需要一种方法在恢复时将参数传递回线程.

一个不同的方法可能是事先将所有参数传递给线程,但这可能不是一个选项.

这通常是怎么做的?

编辑

感谢#1的评论,并希望得到我的希望,但请详细说明如何从线程中的对象创建例如对话框以及如何暂停它.

使用Qt 4.8.1和MSVC++ 2010的以下示例代码导致:

MyClass::MyClass created 
MainWindow::MainWindow thread started 
MyClass::start run 
ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", file kernel\qwidget.cpp, line 1299
Run Code Online (Sandbox Code Playgroud)

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
Run Code Online (Sandbox Code Playgroud)

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "myclass.h"
#include <QThread>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QThread *thread = new QThread();
    MyClass* myObject = new MyClass();

    myObject->moveToThread( thread );
    connect(thread,     SIGNAL( started()),     myObject, SLOT(start()));
    connect(myObject,   SIGNAL( finished()),    thread, SLOT(quit()));
    connect(myObject,   SIGNAL( finished()),    myObject, SLOT(deleteLater()));
    connect(thread,     SIGNAL( finished()),    thread, SLOT(deleteLater()));

    thread->start();
    if( thread->isRunning() )
    {
        qDebug() << __FUNCTION__ << "thread started";
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}
Run Code Online (Sandbox Code Playgroud)

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

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

signals:
    void finished();

public slots:
    void start();

};

#endif // MYCLASS_H
Run Code Online (Sandbox Code Playgroud)

myclass.cpp

#include "myclass.h"

#include <QMessageBox>
#include <QDebug>

MyClass::MyClass(QObject *parent) :
    QObject(parent)
{
    qDebug() << __FUNCTION__ << "created";
}

void MyClass::start()
{
    qDebug() << __FUNCTION__ << "run";

    // do stuff ...

    // get information from user (blocking)

    QMessageBox *msgBox = new QMessageBox();
    msgBox->setWindowTitle(      tr("WindowTitle") );
    msgBox->setText(             tr("Text") );
    msgBox->setInformativeText(  tr("InformativeText") );
    msgBox->setStandardButtons(  QMessageBox::Ok | QMessageBox::Cancel);
    msgBox->setDefaultButton(    QMessageBox::Ok);
    msgBox->setEscapeButton(     QMessageBox::Cancel);
    msgBox->setIcon(             QMessageBox::Information);

    int ret = msgBox->exec();

    // continue doing stuff (based on user input) ...

    switch (ret) 
    {
        case QMessageBox::Ok:
            break;

        case QMessageBox::Cancel:
            break;

        default:
            break;
    }

    // do even more stuff

    emit finished();
}
Run Code Online (Sandbox Code Playgroud)

pau*_*ulm 5

在信号/槽连接中使用Qt :: BlockingQueuedConnection(对QObject :: connect()的调用).

http://doc.qt.digia.com/qt/qt.html#ConnectionType-enum

这将阻止您的线程,直到UI线程上的插槽返回,然后UI线程中的插槽可以自由显示消息框/模式对话框/无论您想要做什么.

必须确保您的工作线程实际上不在UI线程上,因为正如文档所说,如果信号和插槽位于同一线程上,这将导致死锁(因为它将阻塞自身).