Qt小技巧16.信号与lambda的一点小记

1 引言

Qt中用信号连接到一个lambda表达式,可谓十分清爽,简单易懂,但是你觉得你真的就完全会用了?有些坑还是要去踩的。

2 看个例子

这里定义一个QThread子类MyThread,在MainWindow槽函数中启动这个线程,同时将MyThread中的信号连接到一个lambda表达式,例子很简单,代码如下:

2.1 MyThread

#include "MyThread.h"
#include <QDebug>
MyThread::MyThread(QObject *parent) : QThread(parent)
{
}

void MyThread::run()
{
    qDebug() << __FUNCTION__ << QThread::currentThread();
    emit checkDone();
}

2.2 MainWindow

#include "ui_MainWindow.h"
#include "MyThread.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug() << "mainwindow" << QThread::currentThread();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    MyThread *thread = new MyThread(this);
    connect(thread, &MyThread::checkDone, this,  [=] {
            qDebug() << __FUNCTION__ << QThread::currentThread();
    });
    thread->start();
}

2.3 看看打印结果


此时,lambda表达式中的代码在主线程中执行,这个没啥毛病。
现在我们把代码修改下,把connect中的this去掉:

void MainWindow::on_pushButton_clicked()
{
    MyThread *thread = new MyThread(this);
    connect(thread, &MyThread::checkDone, [=] {
            qDebug() << __FUNCTION__ << QThread::currentThread();
    });
    thread->start();
}

再来看看打印结果:

是不是有点惊喜,此时,lambda表达式中的代码没在主线程中执行了,和MyThread::run在一个线程。

2.4 简单分析下

我们先来看看connect函数的原型:

这个就是加了this和没加this的区别,两个函数的原型是不同的。
需要注意的是,加了this这个函数原型参数是const QObject *context,指的是上下文,含义上和const QObject *receiver是不一样的,这点务必要理解。
这样就好懂了,加了this,默认就是自动连接方式,所以lambda表达式中的代码会在主线程中执行,如果没加this,那么lambda表达式中的代码会在发出信号的那个线程中执行,这就是区别。

3 总结

虽然lambda表达式很方便、也很强大,但是很多人在使用的过程中,由于不清楚里面的原理,经常会遇到程序异常现象,比如在子线程中操作了界面,稀里糊涂的就进行了跨线程操作,殊不知这个看似平常的操作隐藏着巨大隐患。如果程序中大量用到lambda表达式,排查错误自然也会变得更加麻烦,好啦,就说这么多,有不对的地方欢迎大家批评指正。

posted @ 2022-09-29 18:13  Qt小罗  阅读(356)  评论(0编辑  收藏  举报