qt中的信号和槽机制本质上是应用了观察者模式进行设计的
1.qt中的信号和槽
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
Qt::ConnectionType = Qt::AutoConnection
如果接收器位于发出信号的线程中,则使用Qt::DirectConnection。否则,将使用Qt::QueuedConnection。连接类型在发出信号时确定。
即绑定信号和槽函数,用信号触发槽函数执行
2.观察者模式解析信号和槽
这里被观察者的Notify(),即为一个signal,观察者的Updata()即为slot,connect函数把观察者和被观察者连接,从而达到signal触发slot的目的,实现解耦合
3.信号和槽的使用
connect(this, &Widget::sig1, this, &Widget::slot1);
void Widget::on_pushButton_clicked()
{
qDebug()<<"sig1 begin";
emit sig1();
QThread::sleep(3);
qDebug()<<"sig1 end";
}
void Widget::slot1()
{
for(int i=0; i <3; ++i)
{
qDebug()<<QString("in for: %1").arg(i);
QThread::sleep(1);
}
qDebug()<<"slot1";
}
运行结果
sig1 begin
“in for: 0”
“in for: 1”
“in for: 2”
slot1
sig1 end
将Qt::ConnectionType type改为Qt::QueuedConnection后
void Widget::slot1()
{
int i=0;
while(true)
{
qDebug()<<QString("in while: %1").arg(++i);
QThread::sleep(1);
}
qDebug()<<"slot1";
}
运行结果
sig1 begin
sig1 end
“in for: 0”
“in for: 1”
“in for: 2”
slot1
从以上运行结果可以知道,emit 信号后,当connect不设置Qt::ConnectionType,默认的AutoConnection会将类型设置为DirectConnection,此模式必须等槽函数执行完毕,当前流程才能向下正常运行,即需要槽函数立即执行完,当前发射信号的流程阻塞,Qt::ConnectionType type改为Qt::QueuedConnection后,即不需要阻塞当前流程,当前函数执行完毕才会执行槽函数,即qt把信号放入信号连接的队列
4.解析DirectConnection 和 QueuedConnection
用观察者模式解释:
DirectConnection:为在SomeoneOperation()中直接调用信号函数,信号函数中Notify()中把槽函数执行完才返回,继而SomeoneOperation()函数才能执行完毕
QueuedConnection:为在SomeoneOperation()中,把信号函数添加到信号队列中,当前SomeoneOperation()添加后继续执行,另外有个线程专门检测信号队列,检测到Notify()后执行
本质上,所谓的阻塞非阻塞即为同步与异步处理信号
与Windows API的比较
信号队列,DirectConnection,QueuedConnection的绑定信号与槽函数与 Windows API SendMessage 和PostMessage相同功能