我正在使用带MyObject->moveToThread(myThread);
的QThread进行需要一段时间的通信功能。一些Signals和Slots会在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
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
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;
}
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
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();
}
答案 0 :(得分:5)
在信号/槽连接中使用Qt :: BlockingQueuedConnection(对QObject :: connect()的调用)。
http://doc.qt.digia.com/qt/qt.html#ConnectionType-enum
这会阻塞你的线程,直到UI线程上的插槽返回,然后UI线程中的插槽可以自由显示消息框/模态对话框/无论你想做什么。
你必须确保你的工作线程实际上不在UI线程上,因为正如文档所说,如果信号和插槽在同一个线程上,这将导致死锁(因为它将阻止自己)。
答案 1 :(得分:2)
我现在不能提供任何具体代码,但我会这样做:
MyClass::start()
锁定QMutex
。messageBoxRequired()
。QWaitCondition
。这也将在线程等待时解锁互斥锁。showMessageBox()
,显示消息框。MyClass
的成员中。您可以通过提供使用互斥锁的setter和getter来保护成员。显然MyClass
本身应该只使用那些setter / getters本身访问该成员。 (另请参阅QMutexLocker)。wakeOne()
上致电wakeAll()
或QWaitCondition
。wait()
调用将返回,MyClass::start()
将继续执行。如果我正确理解文档,QWaitCondition
会在从wait()
返回之前再次锁定互斥锁。这意味着您必须在wait()
调用后直接解锁互斥锁。线程安全setter / getter的实现如下:
void MyClass::setVariable( int value )
{
QMutexLocker( &_mutex );
_value = value;
}
int MyClass::getVariable() // Not sure if a 'const' modifier would work here
{
QMutexLocker( &_mutex );
return _value;
}