我找到了一个旧线程,它几乎可以为我回答这个问题,它的链接可以在这里找到 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/