打印
[应用相关]

TouchGFX 中 Callback 模板实现原理

[复制链接]
2555|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前言
TouchGFX MCU 带来了炫彩丰富的 GUI 界面, 使得基于 STM32 芯片的人机
界面开发非常方便而友好, 比如可以在
TouchGFX Designer 中创建一个按键,
interaction 中给按键添加响应; 或者创建多个界面, 在界面间进行切换; 这些
功能由
designer 帮我们自动生成代码实现了, 那与之对应的功能响应代码具体是
如何实现的呢?
TouchGFX 是用 C++编写的,借助 C++的模板特性, TouchGFX 定义了一组
Callback 模板,基于此模板来实现上述响应的功能。
Callback 模板
TouchGFX 中, Callback 模板的描述放在 Callback.hpp 文件中, 在此定义了
两组模板:
GenericCallback Callback 模板。  

使用特权

评论回复
沙发
盗铃何须掩耳|  楼主 | 2022-1-26 10:19 | 只看该作者
下面是 execute 函数带 1 个参数的 GenericCallback 模板:  

template <class T1>
class GenericCallback
{
public:
virtual ~GenericCallback()
{ }virtual void execute(T1 val1) = 0;
virtual bool isValid() const = 0;
};
Callback 模板组
Callback 模板由 GenericCallback 派生而来。 Callback 模板组也有 4 个模板,分别对应于包含不同参数个数 execute 函数的 GenericCallback 模板, 继承关系如
下图:
下面是 execute 函数带 1 个参数的 Callback 模板:
template <class dest_type, typename T1>
struct Callback<dest_type, T1, void, void> : public GenericCallback<T1>
{
Callback() : pobject(0), pmemfun_1(0) { }
Callback(dest_type* pobject, void (dest_type::*pmemfun_1)(T1))
{
this->pobject = pobject;
this->pmemfun_1 = pmemfun_1;
Figure 1 Callback 继承关系}
virtual void execute(T1 t1)
{
(pobject->*pmemfun_1)(t1);
}
virtual bool isValid() const
{
return (pobject != 0) && (pmemfun_1 != 0);
}
private:
dest_type* pobject;
void (dest_type::* pmemfun_1)(T1);
};
在 Callback 结构中定义了两个私有的成员指针, pobject 为 dest_type 类型对象
的指针, pmemfun_1 为 dest_type 对象的成员函数指针,是指向 dest_type 类型
的成员函数。 这样当 Callback 结构初始化好了以后,再调用 execute 函数时,就
是直接调用了 dest_type 类型对象的成员函数 pmemfun_1。
在使用 Callback 模板时, 根据模板的特性, C++编译器会自动选择最准确的模板
匹配,来生成对应的模板类或模板函数。 因此在使用 Callback 模板时,可以使用
不同的类型参数个数来匹配使用不同的模板。



使用特权

评论回复
板凳
盗铃何须掩耳|  楼主 | 2022-1-26 10:20 | 只看该作者
Callback 模板在 TouchGFX 中的使用
页面切换 - pendingScreenTransitionCallback
TouchGFX 启动过程中会初始化 MVPApplication 对象,在 MVPApplication
类中定义了一个成员 pendingScreenTransitionCallback, 它是
GenericCallback<>*类型的指针, 并初始化为 0
TouchGFX 会调用 handlePendingScreenTransition 函数进行页面切换,最终调
evaluatePendingScreenTransition 函数,在此函数中会用 isValid()函数来检
Callback 是否已经初始化; 如果初始化了,就调用 execute 函数 (因为
Callback GenericCallback<>*类型,因此 execute 函数不带参数)   

void evaluatePendingScreenTransition()
{
if (pendingScreenTransitionCallback &&
pendingScreenTransitionCallback->isValid())
{
pendingScreenTransitionCallback->execute();
pendingScreenTransitionCallback = 0;
}
}
具体的页面切换过程(进入第一个 screen) :
在 TouchGFX 初始化过程中, 会初始化 FrontendApplication 对象 app, 在此对
象的基类中包含一个 transitionCallback 成员, 其类型为:
touchgfx::Callback<FrontendApplicationBase> transitionCallback
在进入第一个 Screen 时, 会调用 app.gotoScreen1ScreenNoTransition(), 在此
函数中,会将 pendingScreenTransitionCallback 设置为指向 transitionCallback
的指针,最终由 TouchGFX 框架调用 execute 函数,执行 makeTransition 完成
页面的切换。
// 初始化 FrontendApplicationBase::transitionCallback, transitionCallback 的私
有成员初始化:
// pobject 赋值为 this(指向 FrontendApplicationBase)
// pmemfun_1 赋值为
&FrontendApplication::gotoScreen1ScreenNoTransitionImpl
void FrontendApplicationBase::gotoScreen1ScreenNoTransition()
{
transitionCallback = touchgfx::Callback<FrontendApplicationBase>(this,
&FrontendApplication::gotoScreen1ScreenNoTransitionImpl);
pendingScreenTransitionCallback = &transitionCallback;
}
//execute 函数内实际执行的函数(pobject->*pmemfun_1)(),即为如下函数:
void FrontendApplicationBase::gotoScreen1ScreenNoTransitionImpl()
{
makeTransition<Screen1View, Screen1Presenter, touchgfx::NoTransition,
Model >(¤tScreen, ¤tPresenter, frontendHeap, ¤tTransition,
&model);
}


使用特权

评论回复
地板
盗铃何须掩耳|  楼主 | 2022-1-26 10:21 | 只看该作者
按键响应 - flexButtonCallback
TouchGFX designer 中创建一个按键,并设置 interaction 后,会在
MainViewBase 类中创建两个私有成员:
//按键响应函数,实现用户的动作响应
void flexButtonCallbackHandler(const touchgfx::AbstractButtonContainer& src)
//Callback 对象
touchgfx::Callback<MainViewBase, const touchgfx::AbstractButtonContainer&>
flexButtonCallback
以及一个按键成员,例如 clickButton
touchgfx::TextButtonStyle< touchgfx::ImageButtonStyle<
touchgfx::ClickButtonTrigger > > 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 也有一定帮助。  

使用特权

评论回复
5
foxsbig| | 2022-1-27 10:50 | 只看该作者
很赞,确实有些帮助

使用特权

评论回复
6
豌豆爹| | 2022-1-27 14:56 | 只看该作者
赞赞赞

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

48

主题

376

帖子

0

粉丝