你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】TouchGFX 中 Callback 模板实现原理

[复制链接]
STMCU小助手 发布时间:2022-2-18 23:02
前言
TouchGFX 为 MCU 带来了炫彩丰富的 GUI 界面,使得基于 STM32 芯片的人机界面开发非常方便而友好,比如可以在 TouchGFX Designer 中创建一个按键,在 interaction 中给按键添加响应;或者创建多个界面,在界面间进行切换;这些功能由 designer 帮我们自动生成代码实现了,那与之对应的功能响应代码具体是如何实现的呢?
TouchGFX 是用 C++编写的,借助 C++的模板特性,TouchGFX 定义了一组Callback 模板,基于此模板来实现上述响应的功能。

Callback 模板
在 TouchGFX 中,Callback 模板的描述放在 Callback.hpp 文件中,在此定义了两组模板:GenericCallback 与 Callback 模板。

GenericCallback 模板组
GenericCallback 为 Callback 模板的模板基类。在 GenericCallback 模板中,定义了两个接口函数:isValid 与 execute;其中 isValid 是来检测 Callback 是否被初始化过,而 execute 函数用于调用实际要执行的函数。GenericCallback 模板组总共定义了 4 个模板,模板之间的差别在于 execute 函数的参数个数不同,4个模板分别对应 execute 函数带有 0 个参数,1 个参数,2 个参数与 3 个参数。本文中仅列出 execute 带一个参数的情况。

下面是 execute 函数带 1 个参数的 GenericCallback 模板:
  1. template
  2. class GenericCallback
  3. {
  4. public:
  5. virtual ~GenericCallback()
  6. {
  7. }
  8. virtual void execute(T1 val1) = 0;
  9. virtual bool isValid() const = 0;
  10. };
复制代码

Callback 模板组
Callback 模板由 GenericCallback 派生而来。Callback 模板组也有 4 个模板,分别对应于包含不同参数个数 execute 函数的 GenericCallback 模板,继承关系如下图:

LH1L0XH(MS(ZZT15{_2O]FE.png

下面是 execute 函数带 1 个参数的 Callback 模板:
  1. template <class dest_type, typename T1>
  2. struct Callback : public GenericCallback
  3. {
  4. Callback() : pobject(0), pmemfun_1(0) { }
  5. Callback(dest_type* pobject, void (dest_type::*pmemfun_1)(T1))
  6. {
  7. this->pobject = pobject;
  8. this->pmemfun_1 = pmemfun_1;
  9. Figure 1 Callback 继承关系
  10. }
  11. virtual void execute(T1 t1)
  12. {
  13. (pobject->*pmemfun_1)(t1);
  14. }
  15. virtual bool isValid() const
  16. {
  17. return (pobject != 0) && (pmemfun_1 != 0);
  18. }
  19. private:
  20. dest_type* pobject;
  21. void (dest_type::* pmemfun_1)(T1);
  22. };
复制代码

在 Callback 结构中定义了两个私有的成员指针,pobject 为 dest_type 类型对象的指针,pmemfun_1 为 dest_type 对象的成员函数指针,是指向 dest_type 类型的成员函数。这样当 Callback 结构初始化好了以后,再调用 execute 函数时,就是直接调用了 dest_type 类型对象的成员函数 pmemfun_1。

在使用 Callback 模板时,根据模板的特性,C++编译器会自动选择最准确的模板匹配,来生成对应的模板类或模板函数。因此在使用 Callback 模板时,可以使用不同的类型参数个数来匹配使用不同的模板。

Callback 模板在 TouchGFX 中的使用
页面切换 - pendingScreenTransitionCallback

在 TouchGFX 启动过程中会初始化 MVPApplication 对象,在 MVPApplication类中定义了一个成员 pendingScreenTransitionCallback,它是GenericCallback*类型的指针,并初始化为 0;

TouchGFX 会调用 handlePendingScreenTransition 函数进行页面切换,最终调用 evaluatePendingScreenTransition 函数,在此函数中会用 isValid()函数来检查 Callback 是否已经初始化;如果初始化了,就调用 execute 函数 (因为Callback 为 GenericCallback*类型,因此 execute 函数不带参数) 。
  1. void evaluatePendingScreenTransition()
  2. {
  3. if (pendingScreenTransitionCallback &&
  4. pendingScreenTransitionCallback->isValid())
  5. {
  6. pendingScreenTransitionCallback->execute();
  7. pendingScreenTransitionCallback = 0;
  8. }
  9. }
复制代码

具体的页面切换过程(进入第一个 screen):
在 TouchGFX 初始化过程中,会初始化 FrontendApplication 对象 app,在此对象的基类中包含一个 transitionCallback 成员,其类型为:
touchgfx::Callback transitionCallback
在进入第一个 Screen 时,会调用 app.gotoScreen1ScreenNoTransition(),在此函数中,会将 pendingScreenTransitionCallback 设置为指向 transitionCallback的指针,最终由 TouchGFX 框架调用 execute 函数,执行 makeTransition 完成页面的切换。
// 初始化 FrontendApplicationBase::transitionCallback,transitionCallback 的私有成员初始化:
// pobject 赋值为 this(指向 FrontendApplicationBase)
// pmemfun_1 赋值为
&FrontendApplication::gotoScreen1ScreenNoTransitionImpl
  1. <div>void FrontendApplicationBase::gotoScreen1ScreenNoTransition()</div><div>{</div><div> transitionCallback = touchgfx::Callback<FrontendApplicationBase>(this,</div><div>&FrontendApplication::gotoScreen1ScreenNoTransitionImpl);</div><div> pendingScreenTransitionCallback = &transitionCallback;</div><div>}</div>
复制代码


//execute 函数内实际执行的函数(pobject->*pmemfun_1)(),即为如下函数:
  1. <div>void FrontendApplicationBase::gotoScreen1ScreenNoTransitionImpl()</div><div>{</div><div> makeTransition<Screen1View, Screen1Presenter, touchgfx::NoTransition,</div><div>Model >(&currentScreen, &currentPresenter, frontendHeap, &currentTransition,</div><div>&model);</div><div>}</div>
复制代码



按键响应 - flexButtonCallback
在 TouchGFX designer 中创建一个按键,并设置 interaction 后,会在MainViewBase 类中创建两个私有成员:
//按键响应函数,实现用户的动作响应
void flexButtonCallbackHandler(const touchgfx::AbstractButtonContainer& src)
//Callback 对象
touchgfx::Callback
flexButtonCallback
以及一个按键成员,例如 clickButton:
touchgfx::TextButtonStyle > clickButton;

在 MainViewBase 的构造函数中,会初始化 flexButtonCallback 成员,并且调用clickButton->setAction 函数,设置此按键的 AbstractButton::action 为
flexButtonCallback,
MainViewBase::MainViewBase():flexButtonCallback(this,
MainViewBase::flexButtonCallbackHandler)
其中:
flexButtonCallback 的 pobject 成员初始化为 this(指向 MainViewBase 的指针)
flexButtonCallback 的 pmemfun_1 成员初始化为
&MainViewBase::flexButtonCallbackHandler
由于 flexButtonCallback 的类型是
struct Callback<dest_type, T1, void, void> : public GenericCallback<T1>
因此 flexButtonCallback 的 execute 函数带有一个参数,参数类型为 const touchgfx::AbstractButtonContainer&,最终此参数会传递给flexButtonCallbackHandler 函数。

在程序运行时,点击按键后,TouchGFX 框架会捕获此事件,并在AbstractButton::handleClickEvent 函数中调用 action->execute(*this)函数,最终即执行了 flexButtonCallbackHandler 函数,实现了用户的动作响应。

小结
本文介绍了 TouchGFX 中 Callback 模板的基本原理,并结合两个例子,简要说明了 Callback 模板在框架中的使用方法。只要注意 Callback 的类型、初始化过程,以及最终 execute 函数执行的函数主体,就能理解 Callback 模板了,这对深入理解 TouchGFX 也有一定帮助。

收藏 评论0 发布时间:2022-2-18 23:02

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版