C++ 使用QProgressBar时:无法为位于不同线程中的父线程创建子线程

C++ 使用QProgressBar时:无法为位于不同线程中的父线程创建子线程,c++,qt,C++,Qt,我尝试根据创建QProgressBar。但它的工作非常糟糕(例如,如果我在构造函数中创建QProgressDialog,它将在应用程序运行时立即出现,因此我决定使用QProgressBar)。但有一个问题: 虽然我使用了互联网上的建议。我的代码: UPD![2] // StudentAbsenceTableApp.h using Job = std::function<void ()>; Q_DECLARE_METATYPE(Job) class StudentAbsenceTab

我尝试根据创建QProgressBar。但它的工作非常糟糕(例如,如果我在构造函数中创建QProgressDialog,它将在应用程序运行时立即出现,因此我决定使用QProgressBar)。但有一个问题:

虽然我使用了互联网上的建议。我的代码:

UPD![2]

// StudentAbsenceTableApp.h
using Job = std::function<void ()>;
Q_DECLARE_METATYPE(Job)
class StudentAbsenceTableApp{
public:
    StudentAbsenceTableApp(QWidget *parent = 0);

private:
    Q_SIGNAL void reqLoadFile(const QString& fileName);
    Q_SIGNAL void reqSaveFile(const QString& fileName);
    Q_SIGNAL void reqGui(const Job&);

    bool documentModified;
    QProgressBar *progressBar;
};

// StudentAbsenceTableApp.cpp
StudentAbsenceTableApp::StudentAbsenceTableApp(QWidget *parent)
   : QMainWindow(parent)
{
    // ...

    setStatusBar(new QStatusBar(this));

    qRegisterMetaType<Job>();
    progressBar = new QProgressBar(statusBar());
    progressBar->setMinimum(0);
    progressBar->setMaximum(0);
    progressBar->setMaximumWidth(150);
    progressBar->hide();
    statusBar()->addPermanentWidget(progressBar);

    connect(this, &StudentAbsenceTableApp::reqLoadFile, this, [this] (const QString& fileName){
        QtConcurrent::run(this, &StudentAbsenceTableApp::loadFile, fileName);
    });
    connect(this, &StudentAbsenceTableApp::reqGui, [this](const Job & job){
        job();
    });
}

// funtion that emit reqLoadFile(fileName)

bool StudentAbsenceTableApp::loadFile(const QString& fileName)
{
    reqGui([=] () { progressBar->show(); });
    auto xmlParser = XMLParser(model);

    try
    {
        reqGui([&] () {
            xmlParser.read(fileName);
            setCurrentFileName(fileName);
            statusBar()->showMessage(tr("Файл загружен"), 2000);
            documentModified = false;
        });
    }
    catch(FileOpenException)
    {
        reqGui([=] () {
            QMessageBox::warning(this, "Ошибка!", "Ошибка открытия файла!", QMessageBox::Ok);
            statusBar()->showMessage(tr("Загрузка отменена"), 2000);
        });
        return false;
    }
    catch(FileReadException)
    {
        reqGui([=] () {
            QMessageBox::warning(this, "Ошибка!", "Ошибка чтения файла!", QMessageBox::Ok);
            statusBar()->showMessage(tr("Загрузка отменена"), 2000);
        });
        return false;
    }

    reqGui([=] () { progressBar->hide(); });
    return true;
}
//StudentAbsenceTableApp.h
使用Job=std::function;
Q_DECLARE_元类型(作业)
班级学生BSCENCETABLEAPP{
公众:
StudentAbsenceTableApp(QWidget*parent=0);
私人:
Q_信号无效重新加载文件(常量Q字符串和文件名);
Q_信号无效请求保存文件(常量QString和文件名);
Q_信号无效请求GUI(施工作业&);
布尔文档修改;
QProgressBar*progressBar;
};
//StudentAbscenceTableApp.cpp
StudentAbsenceTableApp::StudentAbsenceTableApp(QWidget*父项)
:QMainWindow(父级)
{
// ...
setStatusBar(新的QStatusBar(本));
qRegisterMetaType();
progressBar=新的QProgressBar(statusBar());
进度条->设置最小值(0);
进度条->设置最大值(0);
进度条->设置最大宽度(150);
progressBar->hide();
statusBar()->addPermanentWidget(progressBar);
连接(this,&StudentAbsenceTableApp::reqLoadFile,this,[this](常量QString&fileName){
QtConcurrent::run(this,&StudentAbsenceTableApp::loadFile,fileName);
});
连接(this,&StudentAbsenceTableApp::reqGui,[this](const作业和作业){
job();
});
}
//发出reqLoadFile(文件名)的函数
bool StudentAbsenceTableApp::loadFile(常量QString和文件名)
{
reqGui([=](){progressBar->show();});
自动xmlParser=xmlParser(模型);
尝试
{
reqGui([&](){
read(文件名);
setCurrentFileName(文件名);
statusBar()->showMessage(tr(“Фаззззжжж”),2000年);
documentModified=false;
});
}
捕获(FileOpenException)
{
reqGui([=](){
QMessageBox::warning(这是“OfymessageBox!”、“OfymessageBox::Ok”);
statusBar()->showMessage(tr(“аазааазааааааа1072;
});
返回false;
}
捕获(FileReadException)
{
reqGui([=](){
QMessageBox::warning(这句话是“好的”、“好的”);
statusBar()->showMessage(tr(“аазааазааааааа1072;
});
返回false;
}
reqGui([=](){progressBar->hide();});
返回true;
}
我不知道如何编写代码,这是可以编译的,因为有很多代码。

No
QWidget
(和派生类)由Qt提供的方法是线程安全的。因此,除了GUI线程之外,您无法从任何线程访问
QProgressBar
或任何其他小部件

experimentFunction
在非GUI线程中运行,因此不能访问小部件。您必须找到其他通信方式,例如使用信号和插槽。回想一下,您可以在
experimentFunction
中自由地发出信号,因为信号实现是契约线程安全的

一切都很简单,你不需要未来的观察者。在试图“修复”问题的过程中,您已经无望地组合构建了代码

有关跨线程安全调用方法的其他方法,请参阅和

//https://github.com/KubaO/stackoverflown/tree/master/questions/thread-progress-future-44445248
#包括
#包括
#包括
#包括
结构FileOpenException:std::exception{};
struct FileReadException:std::exception{};
结构模型{};
结构XMLParser{
XMLParser(Model&){}
无效读取(常量QString&){
静态结果;
QThread::sleep(3);
切换(结果+++%3){
案例0:返回;
案例1:抛出FileOpenException();
案例2:抛出FileReadException();
}
}
};
使用Job=std::function;
Q_DECLARE_元类型(作业)
class StudentAbscenceTable:公共QMainWindow{
Q_对象
QStatusBar m_statusBar;
QProgressBar m_进度;
QPushButton m_start{“启动并发任务”};
m_模型;
bool m_documentModified={};
公众:
StudentAbsenceTable(){
qRegisterMetaType();
m_statusBar.addPermanentWidget(&m_进度);
m_进度设定最小值(0);
m_进度设置最大值(0);
m_进度设定最大宽度(150);
m_progress.hide();
设置状态栏(&m_状态栏);
setCentralWidget(&m_start);
连接(&m_start,&QPushButton::单击,此,[this]{
m_start.setEnabled(错误);
QtConcurrent::run(this,&StudentAbsenceTable::loadFile);
});
连接(this,&studentAbscenceTable::reqGui,this,[this](常量作业和作业){
job();
});
}
私人:
bool加载文件(){
reqGui([=]{m_progress.show();});
自动文件名=QStringLiteral(“/media/bsuir/data.xml”);
自动xmlParser=xmlParser(m_模型);
试一试{
read(文件名);
reqGui([=]{
setCurrentFileName(文件名);
statusBar()->showMessage(tr(“Фаззззжжж”),2000年);
m_documentModified=假;
});
}
捕获(FileOpenException&){
reqGui([=]{
QMessageBox::warning(这是“OfymessageBox!”、“OfymessageBox::Ok”);
statusBar()->showMessage(tr(“аазааазааааааа1072;
});
}
catch(FileReadException&){
reqGui([=]{
QMessageBox::warning(这句话是“好的”、“好的”);
statusBar()->showMessage(tr(“аазааазаааааааааааааааа;
});
}
reqGui([=]{m_progress.hide();m_start.setEnabled(true);});
返回false;
}
Q_信号无效请求GUI(施工作业&);
vo
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-progress-future-44445248
#include <QtConcurrent>
#include <QtWidgets>
#include <exception>
#include <functional>

struct FileOpenException : std::exception {};
struct FileReadException : std::exception {};
struct Model {};
struct XMLParser {
   XMLParser(Model &) {}
   void read(const QString &) {
      static int outcome;
      QThread::sleep(3);
      switch (outcome++ % 3) {
      case 0: return;
      case 1: throw FileOpenException();
      case 2: throw FileReadException();
      }
   }
};

using Job = std::function<void()>;
Q_DECLARE_METATYPE(Job)

class StudentAbsenceTable : public QMainWindow {
   Q_OBJECT
   QStatusBar m_statusBar;
   QProgressBar m_progress;
   QPushButton m_start{"Start Concurrent Task"};
   Model m_model;
   bool m_documentModified = {};
public:
   StudentAbsenceTable() {
      qRegisterMetaType<Job>();
      m_statusBar.addPermanentWidget(&m_progress);
      m_progress.setMinimum(0);
      m_progress.setMaximum(0);
      m_progress.setMaximumWidth(150);
      m_progress.hide();
      setStatusBar(&m_statusBar);
      setCentralWidget(&m_start);
      connect(&m_start, &QPushButton::clicked, this, [this]{
         m_start.setEnabled(false);
         QtConcurrent::run(this, &StudentAbsenceTable::loadFile);
      });
      connect(this, &StudentAbsenceTable::reqGui, this, [this](const Job & job){
         job();
      });
   }
private:
   bool loadFile() {
      reqGui([=]{ m_progress.show(); });
      auto fileName = QStringLiteral("/media/bsuir/data.xml");
      auto xmlParser = XMLParser(m_model);
      try {
         xmlParser.read(fileName);
         reqGui([=]{
            setCurrentFileName(fileName);
            statusBar()->showMessage(tr("Файл загружен"), 2000);
            m_documentModified = false;
         });
      }
      catch(FileOpenException&) {
         reqGui([=]{
            QMessageBox::warning(this, "Ошибка!", "Ошибка открытия файла!", QMessageBox::Ok);
            statusBar()->showMessage(tr("Загрузка отменена"), 2000);
         });
      }
      catch(FileReadException&) {
         reqGui([=]{
            QMessageBox::warning(this, "Ошибка!", "Ошибка чтения файла!", QMessageBox::Ok);
            statusBar()->showMessage(tr("Загрузка отменена"), 2000);
         });
      }
      reqGui([=]{ m_progress.hide(); m_start.setEnabled(true); });
      return false;
   }
   Q_SIGNAL void reqGui(const Job &);
   void setCurrentFileName(const QString &) {}
};

int main(int argc, char ** argv) {
   QApplication app(argc, argv);
   StudentAbsenceTable ui;
   ui.setMinimumSize(350, 350);
   ui.show();
   return app.exec();
}
#include "main.moc"