我正在尝试更新QProgressDialog(由QMainWindow类拥有)以及执行处理一些耗时操作的QThread。线程在操作期间发出一些信号,以通知调用应用程序有关进展。我希望将线程发出的进度信号连接到QProgressDialog的setValue插槽,以便更新进度条。
它不起作用!不显示进度对话框。如果我在QMainWindow中添加一个插槽并将其连接到工作进度信号以显示线程通过qDebug输出给出的值,我看到信号似乎在线程操作期间被堆叠并且仅在结束时被取消堆叠。线程。
我尝试过DirectConnection连接选项但没有成功。
这是我的代码: qapp.cpp
#include "qapp.h"
#include <threaded.h>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
#include <QProgressDialog>
QApp::QApp(QWidget *parent) :
QMainWindow(parent)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QWidget *window = new QWidget(this);
window->setLayout(mainLayout);
setCentralWidget(window);
QPushButton *button = new QPushButton("Run");
mainLayout->addWidget(button);
connect(button, SIGNAL(clicked(bool)), this, SLOT(doSomeWork()));
}
void QApp::doSomeWork()
{
qDebug() << "do some work";
Threaded worker;
worker.doHeavyCaclulations();
QProgressDialog progressDialog("Copying files...", "Abort Copy", 0, 10000, this);
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setMinimumDuration(0);
progressDialog.setValue(0);
connect(&worker, SIGNAL(progress(int)), &progressDialog, SLOT(setValue(int)));
connect(&worker, SIGNAL(progress(int)), this, SLOT(displayProgress(int)));
worker.wait();
qDebug() << "end of thread";
}
void QApp::displayProgress(int value)
{
qDebug() << "data received" << value;
}
QApp::~QApp()
{
}
threaded.cpp:
#include "threaded.h"
#include <QDebug>
Threaded::Threaded(QObject *parent) : QThread(parent)
{
}
void Threaded::doHeavyCaclulations()
{
if (!isRunning())
{
qDebug() << "start thread" ;
start();
}
}
void Threaded::run()
{
qDebug() << "running big loop";
for(double k = 0 ; k < 10000 ; k++)
{
qDebug() << k;
emit progress(k);
}
}
qapp.h
#ifndef QAPP_H
#define QAPP_H
#include <QMainWindow>
class QApp : public QMainWindow
{
Q_OBJECT
public:
explicit QApp(QWidget *parent = 0);
~QApp();
private:
private slots:
void doSomeWork();
void displayProgress(int value);
};
#endif // QAPP_H
threaded.h
#ifndef THREADED_H
#define THREADED_H
#include <QObject>
#include <QThread>
class Threaded : public QThread
{
Q_OBJECT
public:
explicit Threaded(QObject *parent = 0);
void doHeavyCaclulations();
void run();
private:
signals:
void progress(int value);
public slots:
};
#endif // THREADED_H
此代码的输出,其中k <&lt; 100是:
do some work
start thread
running big loop
0
1
2
3
[...]
97
98
99
end of big loop
end of thread
data received 17
data received 18
data received 19
[...]
data received 99
如果我重新加入 worker.wait(); 由
int k=0;
while(worker.isRunning())
{
qDebug() << "main " << k;
k++;
}
我得到线程的输出和调用方法的输出交错。它确认我的线程与调用方法无关。
对我做错了什么的想法?
答案 0 :(得分:7)
使用QThread
绝对错误。见what is the correct way to implement a QThread... (example please...)。你需要学习线程的基础知识。
你的错误:
1.在本地范围内创建静态线程对象;
2.等待主线程完成;
3.不要启动线程;
4.主线程中的直接调用方法doHeavyCaclulations()
;
5.发出没有工作事件循环的信号,以便传送...
为了您的目的,您需要:
不要继承QThread
。只需使用必要的函数创建简单的Work
类:
class Work: public QObject
{
Q_OBJECT
public:
Work(){};
virtual ~Work(){};
public slots:
void doHeavyCaclulations() { /* do what you need and emit progress signal */ };
signals:
void progress(int);
}
// Then:
void QApp::doSomeWork()
{
//...
QThread* thread = new QThread(parent);
Work* worker = new Work; // Do not set a parent. The object cannot be moved if it has a parent.
worker->moveToThread(thread);
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(started()), worker, SLOT(doHeavyCaclulations()));
connect(worker, SIGNAL(progress(int)), &progressDialog, SLOT(setValue(int)));
thread->start();
//...
}
答案 1 :(得分:3)
QThread
有一个非常重要的事情,你在使用它时必须始终记住 - 只有run()
实际上在一个单独的线程中运行。
每当你创建一个QThread
实例时,这个实例的线程关联(它所属的线程)就是你创建它的同一个线程。什么是最重要的你可能会问我的插槽和信号有什么关系?嗯,这与这些事情有很大关系。因为只有run()
在单独的线程内运行,所以您必须考虑以下事项:
run()
run()
- 访问在插槽内部和run()
内部处理的共享数据需要明确使用线程安全机制,如互斥锁和信号量QThread
也就是说,在某些情况下,您可能需要/必须在QThread
中使用插槽和信号,但这样的实现必须针对控制QThread
的实例而不是它的& #39;实际上是在一个单独的线程中运行(使用run()
)。
Here is a small demo我作为演示如何实现插槽和信号以及使用QObject
与单独的线程进行交互的演示。它采用插槽和信号。请注意,实际上没有必要使用QThread
。您也可以使用QRunnable
作为示例(尽管您必须明确告诉它继承QObject
或使用由您创建的QObject
的单独子类,因为QRunnable
不支持插槽和信号(它不是QObject
的子类)。
使用QObject
的优点是,您可以将其实例移动到更改其线程关联性的线程,以便它完全在该单独的线程中运行(包括插槽)。如果您愿意,还可以将多个QObject
实例放在单个QThread
中。继承QThread
并使用它代替此模型时,您将限制您的选项。
所以我的建议是转储QThread
实现并转到QThread + QObject
(也称为工作者设计模式)的做事方式(针对此特定情况,是)。