TouchGFX之MVP

TouchGFX用户接口遵循Model-View-Presenter(MVP)架构模式,它是Model-View-Controller(MVC)模式的派生模式。 两者都广泛用于构建用户接口应用。

MVP模式的主要优势是:

  • 关注点分离:将代码分成不同的部分提供,每部分有自己的任务。 这使得代码更简单、可重复使用性更高且更易于维护。
  • 单元测试:由于UI的逻辑(Presenter)独立于视图(View),因此,单独测试这些部分会容易很多。

MVP中定义了下列三个类:

  • Model是一种接口,用于定义要在用户界面上显示或有其他形式操作的数据。
  • View是一种被动接口,用于显示数据(来自Model),并将用户指令(事件)传给Presenter以便根据该数据进行操作。
  • Presenter的操作取决于Model和View。 它从存储库(Model)检索数据,并将其格式化以便在视图中显示。

在TouchGFX中,从Model类执行与应用非UI部分(这里称为后端系统)的通信。 后端系统是从UI接收事件和将事件输入UI的软件组件,例如采集传感器的新测量值。 后端系统可作为单独的任务在同一MCU、单独的处理器、云模块或其他硬件上运行。 从TouchGFX的角度来看,这并不十分重要,只要它是能够与之通信的组件。

使用的特定通信协议不受TouchGFX管理。 它只提供一个在每个TouchGFX嘀嗒时间调用一次的函数,可以在其中处理需要的通信。 

从上节内容已知,touchgfx中只有一个Model的实例对象,但每一个屏幕都对应一个View和Presenter的实例对象。

从MVP类的代码可以看出

Model实例对象可以绑定一个ModelListener(用户端Presenter的基类之一)实例对象指针,即Model实例对象可以通过该指针查询到Presenter实例对象。

每个View实例对象可以绑定一个Presenter实例对象指针,即View实例对象可以通过该指针查询到Presenter实例对象。

每个用户端Presenter实例对象(基于ModelListener类)可以绑定Model实例对象指针,即用户端Presenter实例对象可以通过该指针查询到Model实例对象。

用户端Presenter类中包含View实例对象的引用,即用户端Presenter实例对象可以通过该引用查询到View实例对象。

#ifndef MODEL_HPP
#define MODEL_HPPclass ModelListener;/* Model类 */
class Model
{
public:Model();/* 将给定的Presenter对象指针与Model关联起来 */void bind(ModelListener *listener){modelListener = listener;}/* 节拍函数 */void tick();protected:ModelListener *modelListener;		//当前Presenter对象指针
};#endif
#ifndef TOUCHGFX_VIEW_HPP
#define TOUCHGFX_VIEW_HPP#include <touchgfx/Screen.hpp>namespace touchgfx
{
/* View类 */
template <class T>
class View : public Screen
{
public:/* 构造函数 */View() : presenter(0){}/* 将给定的Presenter实例与View关联起来 */void bind(T& newPresenter){presenter = &newPresenter;}protected:T *presenter; //指向与此View关联的presenter的指针
};}#endif
#ifndef TOUCHGFX_PRESENTER_HPP
#define TOUCHGFX_PRESENTER_HPPnamespace touchgfx
{
/* Presenter类 */
class Presenter
{
public:/* 当Presenter由于屏幕进入而变为活动状态时,会自动调用此函数。它通常用于初始化Presenter */virtual void activate(){}/* 当Presenter由于屏幕退出而变为非活动状态时,会自动调用此函数。它通常用于清理Presenter */virtual void deactivate(){}/* 析构函数 */virtual ~Presenter(){}protected:/* 构造函数 */Presenter(){}
};}#endif
#ifndef MODELLISTENER_HPP
#define MODELLISTENER_HPP#include <gui/model/Model.hpp>/* ModelListener类 */
class ModelListener
{
public:/* 构造函数 */ModelListener() : model(0) {}/* 析构函数 */virtual ~ModelListener() {}/* 将Model与Presenter实例关联起来 */void bind(Model *m){model = m;}protected:Model *model;		//Model实例指针
};#endif
#ifndef SCREENPRESENTER_HPP
#define SCREENPRESENTER_HPP
#include <gui/model/ModelListener.hpp>
#include <mvp/Presenter.hpp>using namespace touchgfx;class screenView;/* 用户端某screen对应的Presenter类 */
class screenPresenter : public touchgfx::Presenter, public ModelListener
{
public:...private:...screenView& view;
};#endif

 

通过MVPApplication类的代码可以大概看出引擎是怎么通过MVP切换屏幕的

首先,pendingScreenTransitionCallback不为空,引擎将调用evaluatePendingScreenTransition函数执行切换回调函数(用户需要在切换回调函数中会调用makeTransition)来实现屏幕切换

#ifndef TOUCHGFX_MVPAPPLICATION_HPP
#define TOUCHGFX_MVPAPPLICATION_HPP
#include <new>
#include <common/AbstractPartition.hpp>
#include <mvp/MVPHeap.hpp>
#include <mvp/Presenter.hpp>
#include <touchgfx/Application.hpp>
#include <touchgfx/Callback.hpp>
#include <touchgfx/Screen.hpp>
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/transitions/Transition.hpp>namespace touchgfx
{
class Presenter;/* MVP应用类 */
class MVPApplication : public Application
{
public:/* 构造函数 */MVPApplication() : currentPresenter(0), pendingScreenTransitionCallback(0){instance = this;}/* 执行挂起的屏幕转换回调 */virtual void handlePendingScreenTransition(){evaluatePendingScreenTransition();}protected:Presenter *currentPresenter; //指向当前活动的Presenter对象的指针GenericCallback<>* pendingScreenTransitionCallback; //指向挂起的屏幕转换回调指针/* 执行挂起的屏幕转换回调 */void evaluatePendingScreenTransition(){if(pendingScreenTransitionCallback && pendingScreenTransitionCallback->isValid()){pendingScreenTransitionCallback->execute();pendingScreenTransitionCallback = 0;	//调用完后将指针清空,等待下一次注册}}
};/* 准备屏幕转换:当退出当前屏幕前,需要清理正在活动的一些数据 */
FORCE_INLINE_FUNCTION static void prepareTransition(Screen **currentScreen, Presenter **currentPresenter, Transition **currentTrans)
{/* 卸载屏幕中所有定时的控件 */Application::getInstance()->clearAllTimerWidgets();/* 清理当前Transition */if(*currentTrans){(*currentTrans)->tearDown();}/* 析构当前Transition */if(*currentTrans){(*currentTrans)->~Transition();}/* 清理当前View */if(*currentScreen){(*currentScreen)->tearDownScreen();}/* 清理当前Presenter */if(*currentPresenter){(*currentPresenter)->deactivate();}/* 析构当前View */if(*currentScreen){(*currentScreen)->~Screen();}/* 析构当前Presenter */if(*currentPresenter){(*currentPresenter)->~Presenter();}
}/* 完成屏幕转换:当进入新屏幕后,需要初始化新屏幕的一些数据。然后重绘新屏幕 */
FORCE_INLINE_FUNCTION static void finalizeTransition(Screen *newScreen, Presenter *newPresenter, Transition *newTransition)
{/* 初始化新的View */newScreen->setupScreen();/* 初始化新的Presenter */newPresenter->activate();/* 将新给定的Transition实例与新的View关联起来 */newScreen->bindTransition(*newTransition);/* 初始化新的Transition */newTransition->init();/* 重绘整个屏幕 */newTransition->invalidate();
}/* 用于实现屏幕转换的功能 */
template <class ScreenType, class PresenterType, class TransType, class ModelType>
PresenterType *makeTransition(Screen **currentScreen, Presenter **currentPresenter, MVPHeap& heap, Transition **currentTrans, ModelType *model)
{assert(sizeof(ScreenType) <= heap.screenStorage.element_size() && "View allocation error: Check that all views are added to FrontendHeap::ViewTypes");assert(sizeof(PresenterType) <= heap.presenterStorage.element_size() && "Presenter allocation error: Check that all presenters are added to FrontendHeap::PresenterTypes");assert(sizeof(TransType) <= heap.transitionStorage.element_size() && "Transition allocation error: Check that all transitions are added to FrontendHeap::TransitionTypes");/* 准备屏幕转换:当退出当前屏幕前,需要清理正在活动的一些数据 */prepareTransition(currentScreen, currentPresenter, currentTrans);/* 在相应的内存分区中构建新的Transition、View、Presenter实例 */TransType *newTransition = new (&heap.transitionStorage.at<TransType>(0)) TransType;ScreenType *newScreen = new (&heap.screenStorage.at<ScreenType>(0)) ScreenType;PresenterType *newPresenter = new (&heap.presenterStorage.at<PresenterType>(0)) PresenterType(*newScreen);/* 返回新的Transition、View、Presenter实例对象指针 */*currentTrans = newTransition;*currentPresenter = newPresenter;*currentScreen = newScreen;/* 将新给定的Presenter实例与Model关联起来 */model->bind(newPresenter);/* 将Model与新的Presenter实例关联起来 */newPresenter->bind(model);/* 将新给定的Presenter实例与新的View关联起来 */newScreen->bind(*newPresenter);/* 完成屏幕转换:当进入新屏幕后,需要初始化新屏幕的一些数据。然后重绘新屏幕 */finalizeTransition((Screen *)newScreen, (Presenter *)newPresenter, (Transition *)newTransition);return newPresenter;
}}#endif

 在前端应用基类(FrontendApplicationBase)中,实现了对各种屏幕切换函数的封装

#ifndef FRONTENDAPPLICATIONBASE_HPP
#define FRONTENDAPPLICATIONBASE_HPP
#include <mvp/MVPApplication.hpp>
#include <gui/model/Model.hpp>class FrontendHeap;/* 前端应用基类 */
class FrontendApplicationBase : public touchgfx::MVPApplication
{
public:/* 构造函数 */FrontendApplicationBase(Model& m, FrontendHeap& heap);/* 析构函数 */virtual ~FrontendApplicationBase() { }/* 切换到起始屏幕 */virtual void changeToStartScreen(){gotoscreenScreenNoTransition();}/* 不带任何切换动画切换到screen屏幕 */void gotoscreenScreenNoTransition();protected:touchgfx::Callback<FrontendApplicationBase> transitionCallback;		//切换回调FrontendHeap& frontendHeap;		//前端内存堆引用Model& model;		//Model引用void gotoscreenScreenNoTransitionImpl();	//不带任何切换动画切换到screen屏幕回调执行函数
};#endif
#include <new>
#include <gui_generated/common/FrontendApplicationBase.hpp>
#include <gui/common/FrontendHeap.hpp>
#include <touchgfx/transitions/NoTransition.hpp>
#include <texts/TextKeysAndLanguages.hpp>
#include <touchgfx/Texts.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <platform/driver/lcd/LCD16bpp.hpp>
#include <gui/screen_screen/screenView.hpp>
#include <gui/screen_screen/screenPresenter.hpp>using namespace touchgfx;FrontendApplicationBase::FrontendApplicationBase(Model& m, FrontendHeap& heap): touchgfx::MVPApplication(),transitionCallback(),frontendHeap(heap),model(m)
{touchgfx::HAL::getInstance()->setDisplayOrientation(touchgfx::ORIENTATION_LANDSCAPE);reinterpret_cast<touchgfx::LCD16bpp&>(touchgfx::HAL::lcd()).enableTextureMapperAll();reinterpret_cast<touchgfx::LCD16bpp&>(touchgfx::HAL::lcd()).enableDecompressorL8_All();
}/* 不带任何切换动画切换到screen屏幕 */
void FrontendApplicationBase::gotoscreenScreenNoTransition()
{/* 设置切换屏幕回调 */transitionCallback = touchgfx::Callback<FrontendApplicationBase>(this, &FrontendApplicationBase::gotoscreenScreenNoTransitionImpl);/* 将该切换行为注册到pendingScreenTransitionCallback */pendingScreenTransitionCallback = &transitionCallback;
}/* 不带任何切换动画切换到screen屏幕回调执行函数 */
void FrontendApplicationBase::gotoscreenScreenNoTransitionImpl()
{/* 实现屏幕转换的功能 */touchgfx::makeTransition<screenView, screenPresenter, touchgfx::NoTransition, Model >(&currentScreen, &currentPresenter, frontendHeap, &currentTransition, &model);
}

在前端应用类(FrontendApplication)中,调用model.tick()。即为model提供周期节拍,用来采样UI所需要的数据

#ifndef FRONTENDAPPLICATION_HPP
#define FRONTENDAPPLICATION_HPP
#include <gui_generated/common/FrontendApplicationBase.hpp>class FrontendHeap;using namespace touchgfx;class FrontendApplication : public FrontendApplicationBase
{
public:FrontendApplication(Model& m, FrontendHeap& heap);virtual ~FrontendApplication() { }/* 定时事件 */virtual void handleTickEvent(){model.tick();	//调用model定时事件FrontendApplicationBase::handleTickEvent();	//调用基类定时事件}
private:
};#endif
#include <gui/common/FrontendApplication.hpp>FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap): FrontendApplicationBase(m, heap)
{}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/749045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 排序底层原理解析

前言 本章详细讲下排序&#xff0c;排序在我们业务开发非常常见&#xff0c;有对时间进行排序&#xff0c;又对城市进行排序的。不合适的排序&#xff0c;将对系统是灾难性的&#xff0c;这个不是危言耸听。可能有些人会想&#xff0c;对于排序mysql 是怎么实现的&#xff0c;…

Android 地图SDK 绘制点 删除 指定

问题 Android 地图SDK 删除指定绘制点 详细问题 笔者进行Android 项目开发&#xff0c;对于已标记的绘制点&#xff0c;提供撤回按钮&#xff0c;即删除绘制点&#xff0c;如何实现。 解决方案 新增绘制点 private List<Marker> markerList new ArrayList<>…

Oracle数据库:使用 bash脚本 + 定时任务 自动备份数据

Oracle数据库&#xff1a;使用 bash脚本 定时任务 自动备份数据 1、前言2、为什么需要自动化备份&#xff1f;3、编写备份脚本4、备份脚本授权5、添加定时任务6、重启 crond / 检查 crond 服务状态7、备份文件检查 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

AI赋能写作:AI大模型高效写作一本通

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

Java学习笔记(15)

JDK7前时间相关类 Date时间类 Simpledateformat Format 格式化 Parse 解析 默认格式 指定格式 EE&#xff1a;表示周几 Parse&#xff1a;把字符串时间转成date对象 注意&#xff1a;创建对象的格式要和字符串的格式一样 Calendar日历类 不能创建对象 Getinstance 获取当…

【C#】【SAP2000】读取SAP2000中所有Frame对象在指定工况的温度荷载值到Grasshopper中

if (build true) {// 连接到正在运行的 SAP2000// 使用 COM 接口获取 SAP2000 的 API 对象cOAPI mySapObject (cOAPI)System.Runtime.InteropServices.Marshal.GetActiveObject("CSI.SAP2000.API.SapObject");// 获取 SAP2000 模型对象cSapModel mySapModel mySap…

315曝光黑灰产业链:主板机

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 315晚会曝光主板机黑灰产业链&#xff0c;主板机是什么呢?可能很多人还不知道。在这里松松给大家普及一下&#xff0c;也欢迎大家关注卢松松哟! 主板机是什么呢? 通过报废手机的主板&#xff0c;拆出来后组装成主…

专升本 C语言笔记-06 常用的3种输入输出函数

1.scanf() 与 printf() 的使用 scanf() 格式化输入数据 格式:scanf("格式控制字符串",参数地址列表) scanf("%d,%d,%d",&a,&b,&c); printf("a %d\n",a); printf("b %d\n",b); printf("c %d\n",c); 注意 注…

【数据结构】堆

目录 一、树的介绍以及堆 1.树 2.二叉树以及堆 二、堆的实现 1.heap.h 2.heap.c 1)堆的初始化和销毁 2&#xff09; 堆的插入 3&#xff09;堆的删除 4&#xff09;取堆顶数据 5&#xff09;堆的数据个数 6&#xff09;堆的判空 3.test.c 一、树的介绍以及堆 …

跨境电商选品实战——Ownips公开数据信息安全采集+Python爬虫轻松搞定Lazada电商选品

文章目录 一、引言二、Lazada电商平台选品实战2.1、分析Lazada电商平台的商品列表接口2.2、定位商品列表计算逻辑2.3、封装高质量住宅IP2.4、运行爬虫 三、数据处理及选品分析四、Ownips——企业级全球静态住宅IP&#xff0c;高效采集公开数据 一、引言 互联网与外贸的结合&am…

Maya自定义工具架

有时候我们需要自己定义工具架上的内容&#xff0c;比如将一个工具放到工具架上&#xff0c;或者删除一个工具 添加一个工具 例如我们想在多边形建模栏位上添加一个分离按钮&#xff0c;默认 1 先切换到想要添加的工具架栏位 2 打开菜单&#xff0c;找到我们想添加的工具 …

70城市房价同比继续下降

据北京商报的最新报道&#xff0c;昨&#xff08;3月15日&#xff09;天国家统计局发布《2月70个大中城市商品住宅销售价格》显示&#xff0c;2024年2月&#xff0c;在70个大中城市中&#xff0c;各线城市商品住宅销售价格同比继续下降。 一线城市二手住宅销售价格同比下降6.3…

拿捏指针(二)

个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 目录 前言 数组与指针 数组名的理解 指针数组与数组指针 指针数组 数组指针 数组传参 一维数组传参的本质 二维数组传参的本质 二维数组…

RIPGeo参文31—36(关于对比学习):鼓励对同一数据点进行各种增强(视图),以学习更健壮的表示

RIPGeo中有: —干扰参数。在内部最大化中,我们提出了步骤,以增加损失的方向更新。我们的方法不是用简单的一步方案最大化内部部分,而是在每次迭代结束时将扰动投影到球面空间上(第2-7行),这允许模型产生更微妙但有价值的扰动[31]。 [31] A. Kurakin, I. J. Goodfellow…

【智能硬件、大模型、LLM 智能音箱】MBO:基于树莓派、ChatGPT 的桌面机器人

MAKER:David Packman/译:趣无尽(转载请注明出处) 这是国外 Maker David Packman 制作的基于树莓派机器人 MBO,该机器人的外观设计灵感来自动漫 Adventure Time 中的机器人 MBO。它具有强大的交互功能,可实现脱机唤醒词检测、调用 ChatGPT 3.5 进行聊天、机器视觉对图像进…

京东云主机+京美建站SaaS版

京美建站SaaS版 京美建站搭建企业网站、小程序、3000精美模板 链接:https://daili.jd.com/s?linkNo57UBX34BZMWGNFYTOCPVUE7SN36CCIPKLTFLPCUCPYBKSYYBIPS2BJ57GP7RACLDHU66X526ZOULMIXL2VN7DT7IHU 京东云主机&#xff0c;安全稳定&#xff0c;性能强劲&#xff0c;新客下单…

(网络安全)一款强大的逆向分析工具,开源!

工具介绍 Ghidra 是由美国国家安全局&#xff08;NSA&#xff09;研究部门开发的软件逆向工程&#xff08;SRE&#xff09;套件&#xff0c;用于支持网络安全任务。包括一套功能齐全的高端软件分析工具&#xff0c;使用户能够在各种平台(Windows、Mac OS和Linux)分析编译后的代…

如何成为一名CCAA审核员?报名复习考试注册实习指南

一、管理体系审核员的注册领域 管理体系审核员包括质量管理体系&#xff08;QMS&#xff09;、环境管理体系&#xff08;EMS&#xff09;、职业健康安全管理体系&#xff08;OHSMS&#xff09;、食品安全管理体系&#xff08;FSMS&#xff09;、危害分析与关键控制点&#xff0…

一文带你了解神经网络是如何学习预测的

文章目录 1、GPT与神经网络的关系 2、什么是神经网络 3、神经网络是如何计算的 数据是如何输入到神经网络中的 神经网络是如何进行预测的 神经网络是如何进行学习的 4、小结 1、GPT与神经网络的关系 GPT想必大家已经耳熟能详&#xff0c;当我们与它进行对话时&#xff0c;通常…

桌面待办,电脑桌面怎么设置待办事项

在忙碌的工作生活中&#xff0c;我们经常会有许多事情需要处理&#xff0c;为了提高工作效率和管理时间&#xff0c;很多人都有一套自己的桌面待办事项管理方法。那么&#xff0c;如何利用电脑桌面待办事项来提高工作效率&#xff0c;电脑桌面怎么设置待办事项呢&#xff1f; …