Qt多线程电子邮件:QObject:无法为不同线程中的父级创建子级

时间:2014-08-29 16:32:06

标签: c++ multithreading qt-creator email-integration

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

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

// EmailThread标题

#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

// EmailThread.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().)

感谢您的考虑!

1 个答案:

答案 0 :(得分:2)

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

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

要解决此问题,您可以使用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

<强> MainWindow.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());
}

<强> MainWindow.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();
}