在QObject方法内生成QWidget

时间:2019-08-31 13:03:06

标签: c++ multithreading qt

我现在正在编写一个程序,该程序必须管理接收请求时创建的许多QWidget,但是我不知道如何在QObject类中创建控件。编译器抱怨“ QObject:无法为处于不同线程中的父级创建子级。”

在Google上工作了一个小时,我尝试了许多方法来解决问题(hereherehere),但没有一个起作用。

以下是一些代码:

// 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();
}

我缺少重要的东西吗?

1 个答案:

答案 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。

希望有帮助!