Vc++ - mfc - mfc中的回调函数

[MFC][原创]回调函数实现流程具体实现过程

 第一步:在类成员中或者全局成员声明回调指针
typedef void(*CallBackDelegate)(int a);//回调函数,CallBackDelegate可以随便取建议取的名字有意义,a是参数,这里可以添加任意多的参数,更多参数可以用个结构体
第二步:注册回调函数,在类成员函数声明一个注册函数
void RegisterCallBack(CallBackDelegate callback); //这里注意参数必须含有回调函数类型
在类的成员函数声明(可以声明为public或者private)
private:
CallBackDelegate mycallback;
实现注册函数
void RegisterCallBack(CallBackDelegate callback)
{
mycallback=callback;
}
假设类中有一个函数叫Dowork()则可以写回调函数调用
void Dowork()
{
//dosomething
//例如
for(int i=0;i<1000000;i++)
mycallback(i);
}
此类结束。
第三步:在另一个类,例如我们常见的对话框类使用回调。
首先在新类中声明函数,注意参数要和上面类回调函数对应。上面类我们暂且称为旧类
public:
static void ShowCallBack(int a);
然后在新类实例化旧类。比如旧类叫A,新类叫B
则可以在B初始化中加入
A a;
a.RegisterCallBack(ShowCallBack);//ShowCallBack这个是B中声明的,名字任意取


B回调实现:
B::ShowCallBack(int a)
{
//对回调过来的数据int a进行处理
}

这里举2个例子,让大家彻底知道其原理。
第一个就是上面完整例子:
自定义类A的头文件:
#pragma once

typedef void(*CallBackDelegate)(int a);

class A

{

public:

A();

~A();

void RegisterCallBack(CallBackDelegate callback); //这里注意参数必须含有回调函数类型

void Dowork();

private:

CallBackDelegate mycallback;

};

A.cpp
#include "stdafx.h"

#include "A.h"

A::A()

{

}

A::~A()

{

}

void A::RegisterCallBack(CallBackDelegate callback)

{

mycallback = callback;

}

void A::Dowork()

{

//dosomething

//例如

for (int i = 0; i<1000000; i++)

mycallback(i);

}


对话框类,这里对话框叫CMFCApplication2Dlg
首先声明
public:

CMFCApplication2Dlg(CWnd* pParent = NULL);// 标准构造函数

static void ShowCallBack(int a);
在初始化对话框加入以下代码
BOOL CMFCApplication2Dlg::OnInitDialog()

{

CDialogEx::OnInitDialog();

// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动

//  执行此操作

SetIcon(m_hIcon, TRUE);// 设置大图标

SetIcon(m_hIcon, FALSE);// 设置小图标

// TODO:  在此添加额外的初始化代码

A a;

a.RegisterCallBack(ShowCallBack);//ShowCallBack必须静态函数或者全局函数

return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

}
注意上面还需要引入头文件A,最后对回调函数进行处理
void CMFCApplication2Dlg::ShowCallBack(int a)

{

//处理数据a


第二个例子,回调函数标准是附带一个LPVOID类型回调上下文,,这是为什么呢?因为LPVOID可以将类对象强制转换为指针,这样便可以访问对象控件或者方法,例如对话框,这个和线程为什么传递一个LPVOID类型是一样的,不然不容易访问对话框控件,大体和上面例子差不多。这个例子不是本人原创,但是基本原理一样,参考博客https://blog.csdn.net/fairytailq/article/details/78376414,这里顺便把代码复制过来看一下:
原理: 

参考Button的点击事件。

模块A(Dialog类)需要根据模块B的部分事件(Button点击事件)来实现逻辑,只需要在模块A中实现模块B的回调函数即可(Dialog类实现Button的点击事件)。模块B负责实现回调函数的原型,回调函数的注册。

(注:还可参考C#的事件进行理解,回调函数的原型即C#中的委托Delegate,回调函数的注册可以看成事件Event的注册,A中的回调函数,Event+=Fun中的Fun。)

使用情况: 

如:通信时,异步接收。

例程部分代码说明: 

摘取主要内容,此处我没有在B类中写线程来异步触发回调函数,所以开放接口caller()来外部触发,模拟实际情况。 

注:例程是我缩减整理的,可能有部分错误,了解其精髓即可。

//B.h文件

//回调函数参数结构体

struct tagCallbackParam 

{

public:

    bool        m_bParam0;

    int         m_nParam1;

    CString     m_szParam2;

    tagCallbackParam()

    {

        m_bParam0 = false;

        m_nParam1 = 100;

        m_szParam2 = _T("100");

    }

};

class CB

{

public:

    CB();

    virtual ~CB();

    typedef void(*CallbackPrototype)(LPVOID lp, const tagCallbackParam& rParam);

    void Register(CallbackPrototype pCallBackfun, LPVOID lp);

    void Caller();

private:

    CallbackPrototype m_pFun;

    LPVOID m_lp;

    tagCallbackParam  m_callbackParam;

};

//B.cpp文件

//............

void CB::Register(CallbackPrototype myCallBackfun, LPVOID lp)

{

    //注册回调函数(/类似注册事件)

    m_pFun = myCallBackfun;

    m_lp = lp;

}

void CB::Caller()

{

    //实现一些操作信息

    //..............

    m_callbackParam.m_nParam1++;

    m_callbackParam.m_szParam2.Format(_T("参数2=%d"),m_callbackParam.m_nParam1);

    //触发回调函数(/类似触发事件)

    m_pFun(m_lp, m_callbackParam);

}

//A.h文

//-此处我使用的是窗口类(Dialog.h)

#include "B.h"

//.........

class CB

{

public:

    //............窗口类的一堆声明。

    CB m_cb;

    //回调函数,参数列表,返回值必须和回调函数原型一样,必须是静态,方便在初始化InitDialog时注册。

    static void CallBackDefine(LPVOID lp, const tagCallbackParam& rParam);  

}

//A.cpp

//-此处我添加了两个EditControl(显示参数信息),一个Button(负责触发回调函数)

BOOL A::OnInitDialog()

{

    //......窗口初始化一大推

    m_cb=B();

    m_cb.Register(CallBackDefine,this);

}

//回调函数具体实现

void A::CallBackDefine(LPVOID lp, const tagCallbackParam& rParam)

{

    A* pDlg = (A*)lp;A

    CString szParam1Value;

    szParam1Value.Format(_T("参数1=%d"), rParam.m_nParam1);

    pDlg->GetDlgItem(IDC_EDIT1)->SetWindowTextW(szParam1Value);

    pDlg->GetDlgItem(IDC_EDIT2)->SetWindowTextW(rParam.m_szParam2);

}

void A::OnBnClickedButton1()

{

    m_cb.CallbackUser();

}


————————————————
版权声明:本文为CSDN博主「云未归来」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/FL1623863129/article/details/81210630

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值