我找到了一个旧线程,它接近我回答这个问题,它的链接可以在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().)
感谢您的考虑!
答案 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();
}