C++ 使用QProgressBar时:无法为位于不同线程中的父线程创建子线程
我尝试根据创建QProgressBar。但它的工作非常糟糕(例如,如果我在构造函数中创建QProgressDialog,它将在应用程序运行时立即出现,因此我决定使用QProgressBar)。但有一个问题: 虽然我使用了互联网上的建议。我的代码: UPD![2]C++ 使用QProgressBar时:无法为位于不同线程中的父线程创建子线程,c++,qt,C++,Qt,我尝试根据创建QProgressBar。但它的工作非常糟糕(例如,如果我在构造函数中创建QProgressDialog,它将在应用程序运行时立即出现,因此我决定使用QProgressBar)。但有一个问题: 虽然我使用了互联网上的建议。我的代码: UPD![2] // StudentAbsenceTableApp.h using Job = std::function<void ()>; Q_DECLARE_METATYPE(Job) class StudentAbsenceTab
// 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;
}
我不知道如何编写代码,这是可以编译的,因为有很多代码。NoQWidget
(和派生类)由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"