Qt 中信号槽的连接方式总结

一、信号槽的连接方式

Qt 中信号槽的连接方式,即: QObject::connect() 函数的第五个参数 Qt::ConnectionType,共有五种连接方式。 它决定了是否立刻将特定的信号传递给槽函数,还是将其放在队列中,稍后进行传递。

1. Qt::AutoConnection :自动连接(默认方式)

当第五个参数缺省时默认为该连接方式。具体为:当接收者和发送者位于同一个线程时,等于Qt::DirectConnection;当接收者和发送者位于不同的线程时,等于Qt::QueuedConnection。选择哪一种取决于信号何时被触发。

2. Qt::DirectConnection:直接连接

该方式表示,当信号被触发时,槽函数立刻被调用。 信号的发送和槽函数的执行位于同一个线程中。

3. Qt::QueuedConnection:队列连接

该方式表示:当控制权回到接收者所在线程的事件循环时,槽函数才会被调用。槽函数在接收者所在的线程中执行。在这个过程中信号的发送者和接受者不在同一个线程中,所以发送的信号要先存放于队列中,等到控制权回到接收者所在的线程时,才会在该线程中来执行对应的槽函数。

4. Qt::BlockingQueuedConnection:阻塞连接

该方式与 Qt::QueuedConnection 相同,唯一不同的地方是:发送信号的线程会阻塞,来等待对应的槽函数执行结束,直到槽函数返回,才会继续往下执行。当信号的发送者和接受者位于同一个线程时,禁止使用该连接方式,否则程序会出现死锁。
该连接的一个使用场景是,当需要通过一个GUI程序来启动另一个窗口时,可以先判断当前的线程是否为主线程(即 GUI线程),如果当前线程为GUI线程中,则可以直接像调用普通函数一样来调用对应的槽函数,否则需要通过信号槽的方式来触发对应的信号,等待槽函数在另一个线程中来执行。

QObject::connect(this, &MyObj::SigInfo, this, &MyObj::SlotFunc, Qt::BlockingQueuedConnection);

if(QThread::currentThread() == qApp->thread())
{
    // 当信号在主线程中被触发时,直接调用槽函数
    this->SlotFunc();
}
else
{
    // 当触发信号的时机和槽函数的执行不在一个线程中时,需要通过信号槽的方式来进行触发。
    emit SigInfo();
}

5. Qt::UniqueConnection:唯一连接

该方式表示:信号的发送者和接收者之间只能建立一个连接,如果信号的发送者和接受者之间已经建立了连接,则后续针对该发送者和接收者的任何连接 QObject::connect() 将会失败。且该方式可以和以上四种连接方式的任意一种通过 位或('|') 进行组合使用。


二、QObject::connect 参数说明

1. 信号槽的 sender/receiver 限制

信号槽的发送和接收端都必须是QObject或其派生类对象的指针类型,且派生类中有 Q_OBJECT 宏,才能使用信号槽的机制。

2. receiver 可省略的情况

receiver 只能在槽函数是以下情况时可以省略:

1)、槽函数是 Lambda 表达式时,receiver可省略:
connect(sender, &Sender::valueChanged, [this](const QString &newValue) {});
Lambda 表达式中 []中为捕获的外部变量,如可以捕获当前类对象this,或者捕获除this之外的其它变量如 QWidget* widget等变量:[this, widget] 以便在Lambda函数中使用,()中为与信号中相匹配的参数。

2)、槽函数是静态函数或全局函数时,receiver可省略:
connect(sender, &Sender::valueChanged, OnGlobalFun);

3. 信号槽连接中有重载函数时

以 QComboBox 的 QComboBox::currentIndexChanged(int index)QComboBox::currentTextChanged(const QString &text) 这两个重载为例进行说明。

// 方案1: qOverload<params>() 版本
connect(comboBox, qOverload<int>(&QComboBox::currentIndexChanged),
        this, &MyClass::onIndexChange);

// 方案2: QOverload<params>::of() 版本
connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
        this, &MyClass::onIndexChange);

// 方案3:纯 C++ 函数指针
// 指定函数指针 indexChanged 表示具体哪个信号,然后建立连接
void (*indexChanged)(int) = &QComboBox::currentIndexChanged;
connect(comboBox, indexChanged, this, &MyClass::onIndexChange);

posted @ 2024-04-07 17:48  Jeffxue  阅读(2670)  评论(0)    收藏  举报