输入关键词开始搜索

Qt 信号槽入门

核心概念

信号槽是 Qt 最核心的通信机制,替代传统回调函数。

对象 A                     对象 B
  │                          │
  │  emit signal(data)       │
  │─────────────────────────→│  slot(data)
  │                          │
    信号发出者              槽接收者
    不需要知道谁在听          不需要知道谁发的

connect 的五种写法

// ① Qt4 风格(字符串匹配,编译期不检查 → 不推荐)
connect(sender, SIGNAL(valueChanged(int)),
        receiver, SLOT(onValueChanged(int)));

// ② 函数指针(编译期类型检查 → 推荐)
connect(sender, &Sender::valueChanged,
        receiver, &Receiver::onValueChanged);

// ③ Lambda(最灵活)
connect(sender, &Sender::valueChanged,
        [](int val) { qDebug() << val; });

// ④ Lambda + this 捕获
connect(button, &QPushButton::clicked, this, [this]() {
    m_label->setText("clicked");
});

// ⑤ 信号连接信号
connect(obj1, &Obj1::signalA, obj2, &Obj2::signalB);

连接类型

connect(a, &A::sig, b, &B::slot,
        Qt::AutoConnection);     // 默认:同线程直调,跨线程排队

connect(a, &A::sig, b, &B::slot,
        Qt::DirectConnection);   // 当场调用(发射线程中执行槽)

connect(a, &A::sig, b, &B::slot,
        Qt::QueuedConnection);   // 排队到接收者线程执行

connect(a, &A::sig, b, &B::slot,
        Qt::BlockingQueuedConnection); // 跨线程同步调用(发射者等槽执行完)
类型执行线程使用场景
Auto自动判断默认,大多数情况
Direct发射者线程同线程,实时性要求高
Queued接收者线程跨线程(必须用这个)
BlockingQueued接收者线程跨线程同步调用

自定义信号槽

class Worker : public QObject {
    Q_OBJECT    // ⚠️ 必须加这个宏
public:
    void doWork() {
        emit progressChanged(50);    // 发射信号
        emit finished("done");
    }

signals:       // 信号:只声明,不实现
    void progressChanged(int percent);
    void finished(const QString &result);

public slots:  // 槽:需要实现
    void start() {
        doWork();
    }
};

注意事项

// ❌ 信号和槽的参数类型必须兼容(槽参数可以比信号少)
connect(s, &S::sig(int, string), r, &R::slot(string)); // ❌ 类型不匹配

// ✅ 槽可以忽略尾部参数
connect(s, &S::sig(int, string), r, &R::slot(int));  // ✅ 只用第一个

// ❌ 同一个 connect 重复调用 → 槽被多次触发
// ✅ 用 Qt::UniqueConnection 防止重复
connect(s, &S::sig, r, &R::slot, Qt::UniqueConnection);

// disconnect 断开连接
disconnect(s, &S::sig, r, &R::slot);