我正在使用Qt5,我通过moveToThread()将QObject worker传递给QThread实例来实现一个线程。我的实现看起来像这样..
Worker.h
class worker : public QObject
{
Q_OBJECT
public:
explicit worker(QObject *parent = 0);
bool IsWorkRunning();
void MoveObjectToThread();
signal:
void SignalToObj_mainThreadGUI();
public slots:
void do_Work();
void StopWork();
void StartWork();
private:
void Sleep();
QThread *workerthread;
volatile bool running,stopped;
};
Worker.cpp
worker::worker(QObject *parent) :
QObject(parent),stopped(false),running(false)
{
}
void worker::do_Work()
{
running = true;
while(!stopped)
{
if(running)
{
emit SignalToObj_mainThreadGUI();
workerthread->msleep(20);
}
}
}
void worker::StopWork()
{
running = false;
}
void worker::StartWork()
{
running = true;
}
bool worker::IsWorkRunning()
{
return running;
}
void MoveObjectToThread()
{
workerthread = new QThread;
QObject::connect(workerthread,SIGNAL(started()),this,SLOT(do_Work()));
this->moveToThread(workerthread);
workerthread->start();
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void Startwork_mainwindow();
void Stopwork_mainwindow();
public slots:
private slots:
void on_pushButton_push_to_start_clicked();
void on_pushButton_push_to_stop_clicked();
private:
Ui::MainWindow *ui;
worker myWorker;
bool work_started;
};
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),work_started(false),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork()));
QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_push_to_start_clicked()
{
if(!work_started)
{
myWorker.MoveObjectToThread();
work_started = true;
}
if(!myWorker.IsWorkRunning())
emit this->Startwork_mainwindow();
}
void MainWindow::on_pushButton_push_to_stop_clicked()
{
if(myWorker.IsWorkRunning())
emit this->Stopwork_mainwindow();
}
不知道为什么以下两个信号/插槽对似乎无法正常工作
QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork()));
QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork()));
因此,一旦do_Work()
插槽被QThread对象的started()
信号触发,我就无法启动或停止线程。仅供参考,我的这篇文章是我上一篇文章here described的延续。任何见解都会有所帮助...谢谢
答案 0 :(得分:2)
在MainWindow
班级定义中,尝试将worker myWorker
更改为worker * myWorker
。另外,我会像其他人一样建议并将线程移到worker
类之外。 MainWindow
构造函数变为这样:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, work_started(false)
, ui(new Ui::MainWindow)
, myWorker( new worker() )
{
// NOTE: myWorker is created without a parent on purpose.
// Qt won't change the thread affinity of an obj with a parent
ui->setupUi(this);
connect( this, SIGNAL(Startwork_mainwindow()), myWorker, SLOT(StartWork()) );
connect( this, SIGNAL(Stopwork_mainwindow()), myWorker, SLOT(StopWork()) );
QThread * thread = new QThread();
// delete the worker obj whenever this obj is destroyed
connect( this, SIGNAL(destroyed()), myWorker, SLOT(deleteLater()) );
// stop the thread whenever the worker is destroyed
connect( myWorker, SIGNAL(destroyed()), thread, SLOT(quit()) );
// clean up the thread
connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
myWorker->moveToThread( thread );
thread->start();
}
当然,您不再需要worker::MoveObjectToThread()
方法了。此外,从worker::IsWorkRunning()
调用方法MainWindow
并不安全。你可能不会遇到这个具体例子的任何麻烦,但是当事情变得更复杂时,它肯定会让你感到痛苦。相反,添加workFinished()
信号或类似信号,并在MainWindow
类中进行监听。
Startwork_mainwindow()
信号将开始工作。由于您在调用connect
时未提供连接类型,因此当您更改线程关联(QueuedConnection
)时,Qt将使用moveToThread
。基本上,myWorker
位于具有自己的事件循环的线程中。使用Qt::QueuedConnection
调用一个插槽将事件发布到该事件循环,然后将该方法排队。只要事件循环到达它就会运行。