You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在QT Creator中从外部线程调用GUI函数?信号槽实现遇阻

Qt跨线程向QListWidget添加条目问题修复

原代码存在的核心问题

  1. 信号名称不匹配:构造函数中connect绑定的信号是call_chatReceived,但类中实际声明的信号是call_receivedChat,名称不一致导致信号槽无法触发。
  2. 局部线程类未声明信号:在on_btn_conectar_clicked内定义的ThreadChat类未声明call_receivedChat信号,且局部类无法与外部tela_chat实例正确关联信号逻辑。
  3. 内存泄漏风险:创建的线程对象未做销毁处理,线程结束后会残留内存垃圾。
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 14:13:20