Qt 5:通过信号在QThread工作期间更新QProgressBar

rem*_*ght 1 c++ qt multithreading qt-signals qt5

我正在尝试更新QProgressDialog(由QMainWindow类拥有)沿着执行一些耗时操作的QThread.线程在操作期间发出一些信号,以通知调用应用程序有关进展.我正在寻找将线程发出的进度信号连接到QProgressDialog的setValue槽以更新进度条.

它不起作用!不显示进度对话框.如果我在QMainWindow中添加一个插槽并将其连接到工作进度信号以显示线程通过qDebug输出给出的值,我看到信号似乎在线程操作期间被堆叠并且仅在结束时被取消堆叠.线.

我尝试过DirectConnection connect选项但没有成功.

这是我的代码: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()
{

}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

该代码的输出k <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
Run Code Online (Sandbox Code Playgroud)

如果我重新加入worker.wait(); 通过

 int k=0;
    while(worker.isRunning())
    {
        qDebug() << "main " << k;
        k++;
    }
Run Code Online (Sandbox Code Playgroud)

我得到线程的输出和调用方法的输出交错.它确认我的线程独立于调用方法.

关于我做错了什么的任何想法?

Vla*_*hov 7

绝对错误的使用QThread).看看实现QThread的正确方法是什么......(请举例......).你需要学习线程的基础知识.

您的错误:
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();        
    //...
}
Run Code Online (Sandbox Code Playgroud)