在 QObject 方法中生成 QWidgets

Spawn QWidgets inside a QObject's method

本文关键字:QWidgets QObject 方法      更新时间:2023-10-16

我现在正在制作一个程序,该程序必须管理接收请求时创建的大量QWidgets,但是我不知道如何在QObject类中创建小部件。编译器抱怨"QObject:无法为不同线程中的父级创建子级。

在谷歌上呆了一个小时,我尝试了很多方法来解决问题(这里,这里和这里(,但没有一个奏效。

以下是一些关于它的代码:

// OSD.hpp
#ifndef OSD_HPP
#define OSD_HPP
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
class OSD : public QWidget {
Q_OBJECT
public:
explicit OSD(QWidget *parent = nullptr);
void setText(QString);
const QString getText() const;
private:
QLabel *text;
QVBoxLayout *layout1;
};
#endif // OSD_HPP
// Teller.hpp
#ifndef Teller_HPP
#define Teller_HPP
#include "OSD.hpp"
#include <QObject>
class Teller : public QObject {
Q_OBJECT
public:
explicit Teller(int port, QObject *parent = nullptr);
void SpawnNotification(std::string);
~Teller();
};
#endif // Teller_HPP
// Teller.cpp
class Worker : public QObject {
Q_OBJECT
OSD *o = nullptr;
public:
Worker(){};
~Worker() {
if (o) {
o->deleteLater();
}
};
public slots:
void process() {
o = new OSD; // Problem here
o->setText(QString("Hello"));
o->show();
QThread::sleep(1);
emit finished();
}
signals:
void finished();
};
void Teller::SpawnNotification(std::string){
QThread *thread = new QThread;
Worker *worker = new Worker();
worker->moveToThread(thread);
connect(worker, &Worker::finished, worker, &Worker::deleteLater);
connect(worker, &Worker::finished, thread, &QThread::deleteLater);
connect(thread, &QThread::started, worker, &Worker::process);
thread->start();
}

我错过了什么重要的东西吗?

在Qt中,GUI位于主线程中。Qt文档是这样说的:

GUI 线程和工作线程

如前所述,每个程序在启动时都有一个线程。此线程称为"主线程"(在Qt应用程序中也称为"GUI线程"(。Qt GUI 必须在此线程中运行。所有小部件和几个相关类(例如 QPixmap(在辅助线程中不起作用。辅助线程通常称为"工作线程",因为它用于从主线程卸载处理工作。

(链接: https://doc-snapshots.qt.io/qt5-5.12/thread-basics.html(

您需要在主线程上创建小部件,并将工作线程的信号连接到小部件的插槽。与此类似(未经测试..(:

// Must be called in main thread
void Teller::SpawnNotification(std::string){
QThread *thread = new QThread;
QWidget *widget = new QWidget(nullptr, Qt::WA_DeleteOnClose); // Top-Level window
Worker *worker = new Worker();
worker->moveToThread(thread);
connect(worker, &Worker::finished, worker, &Worker::deleteLater);
connect(worker, &Worker::finished, thread, &QThread::deleteLater);
connect(worker, &Worker::finished, widget, &QWidget::show);
//connect(worker, &Worker::dataReady, widget, &QWidget::setData); // TODO
connect(thread, &QThread::started, worker, &Worker::process);
thread->start();
}

编辑(请参阅下面的评论或 https://doc.qt.io/qt-5/qt.html#ConnectionType-enum(:

另外:Qt需要知道连接跨越不同的线程。因此,您必须将"worker"移动到新线程或显式使用 Qt::QueuedConnection 后进行连接。

希望对您有所帮助!