我现在正在编写一个程序,该程序必须管理接收请求时创建的许多QWidget,但是我不知道如何在QObject类中创建控件。编译器抱怨“ QObject:无法为处于不同线程中的父级创建子级。”
在Google上工作了一个小时,我尝试了许多方法来解决问题(here,here和here),但没有一个起作用。
以下是一些代码:
// 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();
}
我缺少重要的东西吗?
答案 0 :(得分:1)
在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。
希望有帮助!