c++ - 如何从 std::thread 更改 GUI?
问题描述
首先,我尝试使用setVisible()
fromthread
有一个事件:
void MainWindow::OnShow(){
// Start OnShow actions
ui->LoadingBox->setVisible(true);
std::thread dThread(OnShow_threaded, ui, &(this->settingsMap));
dThread.join();
}
有一个功能OnShow_threaded
:
void OnShow_threaded(Ui::MainWindow *ui, std::unordered_map<QString,QString> *settingsMap){
// Connect to server
bool hasInternet = false;
// If app doesn't have Internet access -> show offline mode
if (!hasInternet) {
ui->SettingsLabel->setVisible(true);
}
}
编译带有错误的静态程序集时程序崩溃:
QCoreApplication::sendEvent 中的 ASSERT 失败:“无法向其他线程拥有的对象发送事件。当前线程 0x0x36c56540。在线程 0x0x341c2fa0 中创建了接收器 'WarningMsg'(类型为 'QGroupBox')”,文件 kernel\qcoreapplication.cpp,行558
在线上:ui->SettingsLabel->setVisible(true);
同时,动态链接时也不会出现这样的错误。
你可以在GitHub 上找到完整的项目
其次,我尝试使用事件。
有一个功能OnShow_threaded
:
void OnShow_threaded(MainWindow* mw, Ui::MainWindow *ui, std::unordered_map<QString,QString> *settingsMap){
// Connect to server
bool hasInternet = false;
// If app doesn't have Internet access -> show offline mode
if (!hasInternet) {
MyEvent* event = new MyEvent(EventTypes::InternetConnectionError);
QCoreApplication::postEvent(mw, event);
//delete event;
//delete receiver;
}
}
有一个事件类:
#ifndef EVENTS_HPP
#define EVENTS_HPP
#include <QEvent>
#include <QString>
enum EventTypes {
InternetConnectionError,
Unknown
};
class MyEvent : public QEvent
{
public:
MyEvent(const EventTypes _type) : QEvent(QEvent::User) {_localType = _type;}
~MyEvent() {}
auto localType() const {return _localType;}
private:
int _localType;
};
#endif // EVENTS_HPP
有一个事件处理程序:
void MainWindow::events(QEvent *event)
{
if (event->type() == QEvent::User)
{
MyEvent* postedEvent = static_cast<MyEvent*>(event);
if (postedEvent->localType() == EventTypes::InternetConnectionError){
ui->WarningMsg->setVisible(true);
ui->SettingsLabel->setVisible(true);
}
}
}
传递参数:
void MainWindow::OnShow(){
// Start OnShow actions
ui->LoadingBox->setVisible(true);
std::thread dThread(OnShow_threaded, this, ui, &(this->settingsMap));
dThread.detach();
}
有一个 mainwindows hpp 文件:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QMovie>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QObject>
#include <QMessageBox>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QCoreApplication>
#include <QSaveFile>
#include <QProcess>
#include <thread>
#include <chrono>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "settings.hpp"
#include "events.hpp"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void OnShow();
private slots:
void SettingsLabelPressed();
void on_CloseMsgButton_clicked();
void on_Settings_SaveButton_clicked();
void on_Settings_UseTranslation_stateChanged(int arg1);
protected:
void events(QEvent* event);
private:
Ui::MainWindow *ui;
std::unordered_map<QString,QString> settingsMap;
};
void OnShow_threaded(MainWindow* mw, Ui::MainWindow *ui, std::unordered_map<QString,QString> *settingsMap);
#endif // MAINWINDOW_H
但事件不执行。
我做错什么了?
以及如何从另一个线程正确更改 GUI?
З.Ы. 对不起我的英语,我来自俄罗斯......
解决方案
在 Qt 中,与许多其他 GUI 框架一样,GUI 只能从主线程更新。这意味着如果您想从另一个线程更新 GUI,您必须将其传达给主线程,而主线程又会更新 GUI。
有关更多详细信息,请参阅这些文章:
其他语言的附加资源:Правильная работа с потоками в Qt。
推荐阅读
- laravel - 我在 laravel 8 中有一个属于关系,当我尝试在 tinker shell 中使用该关系时它返回 null
- node.js - Nodejs:验证失败:img:Cast to Buffer 值失败
- javascript - 如何从异步函数返回项目
- c# - Unity OnTriggerEnter2d() 不工作 | 尝试在场景之间切换
- node.js - 将函数 React 组件转换为类组件
- java - 我运行的作业在第一个 InputDialog 后停止工作,我该如何解决?
- java - 连接/断开按钮
- asp.net-core - .NET 5 中多租户应用程序的动态权限值
- python - 删除python pandas中的索引行(不是列)
- linux - do_execve 在将程序加载到内存时是否利用写时复制来分配新页面并创建新的页面映射?