如何在QT Creator中从外部线程调用GUI函数?信号槽实现遇阻
Qt跨线程向QListWidget添加条目问题修复
原代码存在的核心问题
- 信号名称不匹配:构造函数中
connect绑定的信号是call_chatReceived,但类中实际声明的信号是call_receivedChat,名称不一致导致信号槽无法触发。 - 局部线程类未声明信号:在
on_btn_conectar_clicked内定义的ThreadChat类未声明call_receivedChat信号,且局部类无法与外部tela_chat实例正确关联信号逻辑。 - 内存泄漏风险:创建的线程对象未做销毁处理,线程结束后会残留内存垃圾。
- QThread使用不规范:直接继承QThread重写
run的写法虽可行,但Qt更推荐将业务逻辑与线程对象分离的Worker模式,扩展性更强。
方案一:修正继承QThread的写法
修正后的tela_chat.cpp
#include <QThread> #include "tela_chat.h" // 将线程类移到全局/类外部,添加Q_OBJECT宏与信号声明 class ThreadChat : public QThread { Q_OBJECT signals: void call_receivedChat(QString mensagem); protected: void run() override { QString mensagem = "This is what I want to put into QList"; emit call_receivedChat(mensagem); } }; tela_chat::tela_chat(QWidget *parent) : QFrame(parent), ui(new Ui::tela_chat) { ui->setupUi(this); // 修正信号名称,与类声明保持一致 connect(this, SIGNAL(call_receivedChat(QString)), this, SLOT(receivedChat(QString))); } tela_chat::~tela_chat() { delete ui; } void tela_chat::receivedChat(QString mensagem) { ui->lstWdgt_chat->addItem("Professor: " + mensagem); } void tela_chat::on_btn_conectar_clicked() { ThreadChat *thread = new ThreadChat; // 直接将线程信号连接到界面槽 connect(thread, SIGNAL(call_receivedChat(QString)), this, SLOT(receivedChat(QString))); // 线程结束后自动销毁自身,避免内存泄漏 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); }
方案二:推荐的Worker对象模式(Qt官方最佳实践)
这种方式将业务逻辑与线程管理分离,更灵活易扩展。
修改后的tela_chat.h
#include <QFrame> #include <QThread> namespace Ui { class tela_chat; } // 业务逻辑Worker类 class ChatWorker : public QObject { Q_OBJECT public slots: void doWork() { QString mensagem = "This is what I want to put into QList"; emit resultReady(mensagem); } signals: void resultReady(QString mensagem); }; class tela_chat : public QFrame { Q_OBJECT public: explicit tela_chat(QWidget *parent = nullptr); ~tela_chat(); private slots: void receivedChat(QString mensagem); void on_btn_conectar_clicked(); private: Ui::tela_chat *ui; };
修改后的tela_chat.cpp
#include "tela_chat.h" tela_chat::tela_chat(QWidget *parent) : QFrame(parent), ui(new Ui::tela_chat) { ui->setupUi(this); } tela_chat::~tela_chat() { delete ui; } void tela_chat::receivedChat(QString mensagem) { ui->lstWdgt_chat->addItem("Professor: " + mensagem); } void tela_chat::on_btn_conectar_clicked() { QThread *thread = new QThread; ChatWorker *worker = new ChatWorker; // 将Worker对象移到线程中执行 worker->moveToThread(thread); // 线程启动时触发业务逻辑 connect(thread, SIGNAL(started()), worker, SLOT(doWork())); // 业务逻辑完成后将结果发送到界面槽 connect(worker, SIGNAL(resultReady(QString)), this, SLOT(receivedChat(QString))); // 任务完成后销毁Worker与线程 connect(worker, SIGNAL(resultReady(QString)), worker, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); }
关键注意事项
- 信号槽名称、参数类型必须完全匹配,否则无法触发。
- 跨线程信号槽默认使用
Qt::QueuedConnection,确保槽函数在UI线程执行,禁止直接在非UI线程操作UI控件。 - 自定义QObject子类必须添加
Q_OBJECT宏,否则信号槽机制无法正常工作。 - 必须通过
deleteLater()管理线程与Worker对象的内存,避免泄漏。
内容的提问来源于stack exchange,提问作者user21806805
相关产品推荐
相关产品推荐

