QT 回调函数来龙去脉

一、回调函数
  回调函数就是一个通过函数指针调用的函数。A类将一个函数的地址作为参数传给B类的一个函数,此时A类就不用关心这个函数的执行了。当B类里面触发了某个特定的条件,B类调用这个回调函数,进行响应。
  回调函数分为两种,一种是同步回调函数,另一种是异步回调函数。两种回调都可以使得调用者不再依赖于被调用者,使得二者在代码空间分布上解耦,而异步回调函数更是在运行时从时间上将二者解耦。

二、回调函数的例子
在这里插入图片描述
(1)主窗体

//MainWindow.h
public:
	//静态方法的回调函数
    static void setPos(MainWindow *m, const QPointF &r);
    void setLinePos(const QPointF &r);

//MainWindow.cpp------------------------------------------------------
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //widget提升为了子部件
    //把对象实例的指针或引用做为参数传给子部件。就能找到主窗口中的控件。
    ui->widget->setCallbackFunc(this, setPos);
}

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

void MainWindow::setPos(MainWindow *m, const QPointF &r)
{
	//静态函数中,没有this指针,因此需要传当前对象,否则无法拿到lineEdit控件
    m->setLinePos(r);
}

void MainWindow::setLinePos(const QPointF &r)
{
    ui->lineEdit1->setText(QString::number(r.x()));
    ui->lineEdit2->setText(QString::number(r.y()));
}


(2)子部件

//Call.h
public:
    explicit Call(QWidget *parent = nullptr);
    ~Call();

    void setCallbackFunc(MainWindow *m, void(*func) (MainWindow *m, const QPointF &point));
protected:
    void paintEvent(QPaintEvent *event);
    void keyPressEvent(QKeyEvent *event);

private:
    void(*m_callbackFunc)(MainWindow *m, const QPointF &point);
    MainWindow *m_m;


//Call.cpp-----------------------------------------------------
Call::Call(QWidget *parent)
    :QWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
}

Call::~Call()
{
}

void Call::setCallbackFunc(MainWindow *m,void(*func) (MainWindow *m, const QPointF &point))
{
	//保存回调函数地址,以及主窗口对象
    m_m = m;
    m_callbackFunc = func;
}

void Call::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    //想要绘图生效,painter必须关联到画图设备,当前代码中画图设备为this(当前窗口)
    QPainter painter(this);
    painter.setPen(Qt::white);
    painter.setBrush(Qt::red);
    painter.drawRect(0, 0, 50, 50);
}

void Call::keyPressEvent(QKeyEvent *event)
{
	//获取键盘事件,事件触发后,进行移动
    switch(event->key())
    {
        case Qt::Key_Up:
            move(this->x(), this->y() - 20);
            break;
        case Qt::Key_Down:
            move(this->x(), this->y() + 20);
            break;
        case Qt::Key_Left:
            move(this->x() - 20, this->y());
            break;
        case Qt::Key_Right:
            move(this->x() + 20, this->y());
            break;
        default:
            break;
    }
	
	//子部件调用回调函数,将此时的部件坐标告诉对应的主窗口
    m_callbackFunc(m_m, this->pos());
}

三、类内成员函数作为回调函数为什么需要加static?
  在类中封装回调函数,回调函数必须要加上static关键字,这样this指针就不能用了,类中静态函数只能访问类的静态成员,不能访问类中的非静态成员,静态函数属于这个类,而不再仅仅属于具体的对象,类的静态函数中没有默认的this指针。但是为什么要这要做呢?

//1.例如一个回调函数被要求声明为以下形式(不属于具体的对象):
void CALLBACK function();

//2.如果这个函数在类ObjClass里面,编译器会为其添加一个this指针,
//用于指向调用该函数的对象。所以编译出来的代码是这种形式:

void CALLBACK ObjClass::function(ObjClass* this)
{}

函数参数列表与被要求声明的形式不一致。就比如说,主窗口中回调函数中有this指针,但是子部件调用的时候可没有,导致参数不匹配。因此我们应该废弃this,而我们也恰巧需要使用主窗口类中的控件,我们可以把对象实例的指针或引用做为参数,和回调函数地址一并传给子部件。

备注:回调函数也可以声明在类外,全局的传类对象指针给回调函数即可使用类内成员,但是回调函数是全局的,所以会影响类的封装性

四、回调函数存在的信任问题
Node.js 天然的异步特性设计使得大多数接口都是异步的,自然也充满了各种各样的异步回调函数。在 Node.js 里,回调函数最大的问题不仅仅是代码书写上产生了 callback hell,更本质的问题是回调函数的调用得不到有效的控制。因为外部异步接口不都像框架一样是基本可信任的,所以你并不能保证别人会如何对待你传入的回调函数。例如调用者疯狂调用回调函数。有趣的是,异步流程控制协议 Promise 再一次利用控制反转解决了回调函数调用的「信任」问题。Promise 把本来由异步接口控制的回调函数调用权收归自己所有,所有的异步调用都是通过 Promise 这个「中介」来完成,而回调函数的管理和调用也由 Promise 来一手掌握。

参考各位大佬的文章,再次感谢!
百度百科:回调函数
喜欢吃冰棍de谷利文君:Qt错误:Painter not active
菌丶:类中的回调函数要加static的原因
云端的蜗牛:C++回调函数必须为静态函数的原因
lesliefish:在Qt中使用回调函数替代信号槽
一只代码狗的自我修养:完全理解回调函数

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值