Qt中自定义信号需在QObject子类头文件的signals:区块内声明,返回void、不实现;用emit触发;通过connect连接槽函数,支持显式连接、自动连接和Lambda三种方式。

要在Qt中让两个不相关的类之间安全通信,比如子线程加载完资源后通知主线程更新UI,就必须自己定义信号——系统自带的信号覆盖不了这种跨线程、跨模块的业务场景。
自定义信号的声明位置和语法
在继承自QObject的类头文件(.h)中,把信号写在signals:关键字下方:
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
signals:
void taskFinished();
void progressUpdated(int percent);
void errorOccurred(const QString &msg);
};
【必须写在 signals: 区块内,且不能加 public/private 等访问修饰符】
信号函数只声明、不实现;返回值必须是 void;可以带参数,支持重载(比如同时声明 void dataReady(int) 和 void dataReady(QString))。
触发信号:emit 关键字怎么用
在类的成员函数(比如 run() 或某个处理逻辑函数)中,用 emit 触发信号:
void Worker::doWork() {
// 模拟耗时操作
for (int i = 0; i <= 100; i += 10) {
QThread::msleep(100);
emit progressUpdated(i);
}
emit taskFinished();
}
emit 是一个空宏,写不写都能编译通过,但强烈建议保留——它让代码意图一目了然,避免和普通函数调用混淆。
注意:不能在类外部直接 emit 某个对象的信号,必须通过该对象的成员函数调用 emit;也不能对 const 对象 emit 信号。
连接信号到槽的三种方式
方法一:使用 QObject::connect 显式连接(最常用、最清晰)
Worker *worker = new Worker(this);
QThread *thread = new QThread(this);
worker->moveToThread(thread);
// 主线程中连接
connect(worker, &Worker::taskFinished,
this, &MainWindow::onTaskDone);
connect(worker, &Worker::progressUpdated,
this, &MainWindow::updateProgress);
Qt Creator 18.0.2 Windows x86_64 历史版本安装包,适合需要旧版本 IDE、旧项目兼容、Qt/C++ 项目维护、构建套件配置和调试环境回退的用户使用。
方法二:自动连接(基于命名约定,仅限于同一对象内)
如果 Worker 类里有个槽叫 onTaskFinished(),且信号名是 taskFinished(),那么只要在构造函数中调用 connect(this, &Worker::taskFinished, this, &Worker::onTaskFinished),就能自动响应。但这种方式耦合度高,不推荐用于跨对象通信。
方法三:Lambda 表达式作为临时槽(适合简单逻辑、无需单独声明槽函数)
connect(worker, &Worker::errorOccurred,
this, [=](const QString &msg) {
QMessageBox::warning(this, "Error", msg);
});
自定义槽函数的声明与实现
第一步:在类的 public 或 public slots: 区域声明槽函数(Qt5+ 允许直接写在 public 下)
public slots:
void onTaskDone();
void updateProgress(int value);
第二步:在 .cpp 文件中实现这些函数,注意返回值必须是 void
void MainWindow::onTaskDone() {
ui->startButton->setEnabled(true);
ui->statusLabel->setText("任务已完成");
}
第三步:确保槽函数签名与信号参数严格匹配(类型、顺序、数量),否则 connect 会失败且无编译错误——运行时信号发出去,槽却收不到。
【connect 返回 bool 值,务必检查是否为 true,false 表示连接失败】
bool ok = connect(worker, &Worker::taskFinished, this, &MainWindow::onTaskDone);
if (!ok) qWarning() << "Signal-slot connection failed!";

















