c++ - Qt多线程邮件: QObject: Cannot create children for a parent that is in a different thread

标签 c++ multithreading qt-creator email

我找到了一个旧线程,它几乎可以为我回答这个问题,它的链接可以在这里找到 QObject: Cannot create children for a parent that is in a different thread .

我知道这是一个旧线程,但我很难理解在我的情况下将信号和槽放在哪里。我正在编写一个程序,它将通过电子邮件发送警报,我希望它们在线程中运行,这样它们就不会中断主程序和彼此。我创建了一个 EmailThread 类,它继承自 QThread 并实现了 run() 方法。我有另一个类 Smtp.cpp,它成功发送了电子邮件,但仅在主线程中发送。我想在每个 EmailThread 中为每个应该接收电子邮件的地址创建一个 Smtp 类的实例。我还有一个 namespace 来处理我所有的数据库信息。如果出现问题,我希望能够将信息从我的数据库发送到所有输入的电子邮件地址。那么哪个类获得插槽,哪个类发出信号?我将把它们放在哪里,非常感谢能帮助我弄明白的代码示例。

//邮件线程头

#ifndef EMAILTHREAD_H
#define EMAILTHREAD_H

#include <QThread>
#include "smtp.h"

class EmailThread : public QThread
{
  public:
    explicit EmailThread(QString to, QString from, QString subject, QString message);

  signals:

  public slots:

  protected:
      void run();
  private:
      Smtp * emailer;
      QString to;
      QString from;
      QString subject;
      QString message;
};

#endif // EMAILTHREAD_H

//邮件线程.cpp

#include "emailthread.h"

EmailThread::EmailThread(QString emailTo, QString emailFrom, QString   emailSubject, QString emailMessage)
{
  emailer = new Smtp("myaddress@email.com","myPassword", "secure.emailsrvr.com",465, 300000);
  to = emailTo;
  from = emailFrom;
  subject = emailSubject;
  message = emailMessage;
}

void EmailThread::run(){
    emailer->sendMailNoAttachments(from,to, subject, message);
}

调用的邮箱

EmailThread * newEmailThread = new EmailThread("myaddress@email.com","myaddress@email.com", "Subject Test", "This is the message string");
  newEmailThread->start();

我得到了和上面一样的错误,父线程和子线程不一样。这是完整的错误:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSslSocket(0xc6dde0), parent's thread is QThread(0xf52410), current thread is QThread(0xc619c8)
QObject::connect: Cannot queue arguments of type 'QAbstractSocket::SocketState'
(Make sure 'QAbstractSocket::SocketState' is registered using qRegisterMetaType().)

感谢您的考虑!

最佳答案

对 sendMainNoAttachments 的方法调用发生在 EmailThread 类的 run 方法中,这意味着它正确地发生在另一个线程上。但是,您的错误源于您的电子邮件程序是在主/GUI 线程上创建的。

这是因为 QThread 应该被认为是一个“线程管理器”类,因此只有它的 run 方法在它管理的线程上运行。这意味着它的构造函数在调用它的线程上执行。

为了克服这个问题,您可以在运行方法中创建您的电子邮件程序,如果您每次都创建一个新的电子邮件程序没有问题的话。但是,我强烈建议改为使用 QThread 的不同用法,当您希望在不同线程上的对象之间进行交互时,建议这样做。

您将 QObject 子类化并将要在线程中执行的函数移动到其中的槽。然后使用 QObject::moveToThread 将对象移动到线程。如果它的任何槽从排队连接发出信号(如果连接发生在已移动到另一个线程的对象上,这是自动的),它们将在该线程上执行。请注意,对 worker 对象的直接函数调用仍将在主线程上执行。您可以在 documentation for QThread 中阅读更多相关信息.

首先,你可以创建一个标准的QThread。如果它是 QObject 类型,我们可以使用您的 Smtp 类。如果不是,您可以创建一个包装器并通过它路由信号。接下来,您将使用 moveToThread 将 Smtp 实例移动到新线程。然后,您需要将带有消息内容的信号连接到将邮件发送到 Smtp 类的插槽。

下面是一些详细说明可能解决方案的示例代码。

Mailer.cpp

#include "Mailer.hpp"

Mailer::Mailer(QObject* parent) :
  QObject(parent), emailer(45, 300000), thread(this) {
  emailer.moveToThread(&thread);
  thread.start();

  w.show();

  connect(&w, &MainWindow::sendMail,
          &emailer, &Smtp::sendMailNoAttachments);
}

Mailer.hpp

#ifndef MAILER_HPP
#define MAILER_HPP

#include "Smtp.hpp"
#include "MainWindow.hpp"
#include <QObject>
#include <QThread>
#include <memory>

class Mailer : public QObject {
  Q_OBJECT

 public:
  explicit Mailer(QObject* parent = nullptr);

 private:
  Smtp emailer;
  QThread thread;
  MainWindow w;
};

#endif // MAILER_HPP

Smtp.cpp

#include "Smtp.hpp"

Smtp::Smtp(int port, int number, QObject* parent)
  : QObject(parent) {
}

void Smtp::sendMailNoAttachments(const QString& emailTo,
                                 const QString& emailFrom,
                                 const QString& emailSubject,
                                 const QString& emailMessage) {
  // Send that email!
}

Smtp.hpp

#ifndef SMTP_HPP
#define SMTP_HPP

#include <QObject>

class Smtp : public QObject {
  Q_OBJECT

 public:
  explicit Smtp(int port, int number, QObject* parent = nullptr);

 public slots:
  void sendMailNoAttachments(const QString& emailTo,
                             const QString& emailFrom,
                             const QString& emailSubject,
                             const QString& emailMessage);
};

#endif // SMTP_HPP

主窗口.cpp

#include "MainWindow.hpp"
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

MainWindow::MainWindow(QWidget* parent)
  : QMainWindow(parent) {
  QWidget* centralWidget = new QWidget(this);

  QLabel* toLabel = new QLabel(QStringLiteral("To: "));
  toLineEdit = new QLineEdit(centralWidget);

  QLabel* fromLabel = new QLabel(QStringLiteral("From: "));
  fromLineEdit = new QLineEdit(centralWidget);

  QLabel* subjectLabel = new QLabel(QStringLiteral("Subject: "));
  subjectLineEdit = new QLineEdit(centralWidget);

  QLabel* messageLabel = new QLabel(QStringLiteral("Message: "));
  messageTextEdit = new QTextEdit(centralWidget);

  QPushButton* mailButton = new QPushButton(centralWidget);
  mailButton->setText(QStringLiteral("Send Mail"));

  QVBoxLayout* layout = new QVBoxLayout(centralWidget);
  layout->addWidget(toLabel);
  layout->addWidget(toLineEdit);
  layout->addWidget(fromLabel);
  layout->addWidget(fromLineEdit);
  layout->addWidget(subjectLabel);
  layout->addWidget(subjectLineEdit);
  layout->addWidget(messageLabel);
  layout->addWidget(messageTextEdit);
  layout->addWidget(mailButton);

  this->setCentralWidget(centralWidget);

  connect(mailButton, &QPushButton::clicked, this, &MainWindow::prepareMail);
}

void MainWindow::prepareMail() {
  emit sendMail(toLineEdit->text(), fromLineEdit->text(),
                subjectLineEdit->text(), messageTextEdit->toPlainText());
}

主窗口.hpp

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

#include <QMainWindow>
#include <QLineEdit>
#include <QTextEdit>

class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  explicit MainWindow(QWidget* parent = nullptr);

 signals:
  void sendMail(const QString& to, const QString& from,
                const QString& subject, const QString& message);

 public slots:
  void prepareMail();

 private:
  QLineEdit* toLineEdit = nullptr;
  QLineEdit* fromLineEdit = nullptr;
  QLineEdit* subjectLineEdit = nullptr;
  QTextEdit* messageTextEdit = nullptr;
};

#endif // MAINWINDOW_HPP

main.cpp

#include "Mailer.hpp"
#include <QApplication>

int main(int argc, char* argv[]) {
  QApplication a(argc, argv);

  Mailer mailer;

  return a.exec();
}

关于c++ - Qt多线程邮件: QObject: Cannot create children for a parent that is in a different thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25572432/

相关文章:

python - urllib2 urlopen 读取超时/ block

c++ - 如何在 rtl 对齐中打开右侧的子菜单?

c++ - 模板函数调用的ifstream或ofstream类型

以 ~ 开头的 C++ 路径

c# - 如何中止在另一个函数内启动的线程?

c++ - 无法在另一个 Linux 系统上运行可执行二进制文件?

qt - 安装 Qt Quick Components for Desktop 以与 Qt Creator 一起使用

c++ - 不工作 : override the default less-than operator of shared_ptr of a class

c++ - Eigen 中的正确索引

java - 单个 JFrame 中的多线程