1.5 MATLAB App Designer 和 MVC · 2019-01-21 · MATLABAppDesigner教程 27 1.5 MATLAB App...

15
MATLAB App Designer 教程 27 1.5 MATLAB App Designer MVC 通过前⾯⼏节的学习,我们展⽰了 Appdesigner 如下的功能: 新的和⼯业相关的控件 更⽅便的布局⽅法 ⾃动⽣成对应于布局的⾯向对象的代码 App Designer 的显著优点是帮助更⽅便的布局,我们可以把这个优点和 MVC 设计模 式结合起来,也就是说,把 App Designer ⽣成的代码当做 MVC 中的 View 类的出发点,进 ⼀步的更好的组织⽤户界⾯和数据模型。 实例如下:仍然从教程 1 的取款机界⾯出发,本节⽬的要实现这样⼀个 GUI1.26 不⼀样的是,这次我们先设计 Model 类。这更符合思维的习惯,因为总是先有模型,再 考虑如何设计⼀个⽤户界⾯让其和底层模型进⾏互动。 1.5.1 简单回顾什么是 MVC 模式 本节内容来⾃ MATLAB ⾯向对象编程-从⼊门到设计模式第 7.3 MVC Model- View-Controller 的缩写,仔细分析 ATM 界⾯的需求,程序可以被明显地分成两个部分。 第⼀部分可以归结为模型(Model),Model 反映程序的中⼼逻辑,在这⾥很简单,如果 是存款,balance 的计算⽅法为 balance = balance + input 如果是提款,则是 balance = balance - input 程序的第⼆部分可以归结为视图(View),显⽰ User Interface 给⽤户。View 的职责包 : 产⽣ Figure 和控件对象,决定它们放在什么位置,以及设置默认值。

Transcript of 1.5 MATLAB App Designer 和 MVC · 2019-01-21 · MATLABAppDesigner教程 27 1.5 MATLAB App...

MATLAB App Designer 教程 27

1.5 MATLAB App Designer 和 MVC通过前⾯⼏节的学习,我们展⽰了 Appdesigner 如下的功能:

• 新的和⼯业相关的控件

• 更⽅便的布局⽅法

• ⾃动⽣成对应于布局的⾯向对象的代码

App Designer 的显著优点是帮助更⽅便的布局,我们可以把这个优点和 MVC 设计模

式结合起来,也就是说,把 App Designer ⽣成的代码当做 MVC 中的 View 类的出发点,进

⼀步的更好的组织⽤户界⾯和数据模型。

实例如下:仍然从教程 1 的取款机界⾯出发,本节⽬的要实现这样⼀个 GUI:

图 1.26

不⼀样的是,这次我们先设计 Model 类。这更符合思维的习惯,因为总是先有模型,再

考虑如何设计⼀个⽤户界⾯让其和底层模型进⾏互动。

1.5.1 简单回顾什么是 MVC 模式本节内容来⾃ MATLAB ⾯向对象编程-从⼊门到设计模式第 7.3 节 MVC 是 Model-

View-Controller 的缩写,仔细分析 ATM 界⾯的需求,程序可以被明显地分成两个部分。

第⼀部分可以归结为模型(Model),Model 反映程序的中⼼逻辑,在这⾥很简单,如果

是存款,balance 的计算⽅法为

balance = balance + input

如果是提款,则是

balance = balance - input

程序的第⼆部分可以归结为视图(View),显⽰ User Interface 给⽤户。View 的职责包

括:• 产⽣ Figure 和控件对象,决定它们放在什么位置,以及设置默认值。

28 MATLAB 中⽂论坛技术专栏

• 把控件和它们的回调函数联合起来

可以看出,实际编程中,模型反映的是程序的逻辑,是相对稳定的,⽽视图界⾯需要经

常调整,⽽且界⾯的调整不应该影响到程序的模型。采⽤⾯向对象的思想,最显然的做法是

把界⾯和模型封装到不同的类当中去,让各个类各司其职。这叫做把界⾯的变化和模型解耦。

还有⼀些和界⾯模型⽆关的功能,⽐如处理⽤户的输⼊。我们把它们归到第三个类中去,叫

做控制器(Controller)类。这样⽤三个基本的类来组织整个 GUI 程序就是我们要介绍的模

型–视图–控制器 (MVC) 模式。

总的来说,MVC 模式把 GUI 程序分解成三部分,如图所⽰:

图 1.27

• 模型(Model):负责程序的内在逻辑。

• 视图(View):负责构造,展⽰⽤户界⾯。

• 控制器(Controller):负责处理⽤户输⼊。

对于⼀个⽤户事件的响应,基本的流程如上。回调函数在 Controller 中,⾸先由 Con-troller 中的回调函数作出第⼀轮的处理。如果该响应需要涉及程序的内在逻辑,由 Controller负责调⽤ Model 中的相关函数;如果 Model 中的某些内在状态发⽣变化,还需要通知 View对象;View 对象接到通知,查询 Model 的内在状态,并且在界⾯上作出更新,呈现给⽤户。

1.5.2 先设计取款机的 Model 类很明显我们需要⼀个属性叫做 balance 来记录账户的余额,它的初值将来构造函数的初

始输⼊。

MATLAB App Designer 教程 29

classdef Model < handleproperties

balance % 简单起见,把 balance 设置成 public 属性。endmethods

function obj = Model(balance)obj.balance = balance;

endend

end

Model 类必须提供⽅法,来允许外界来改变 balance 的值,于是需要分别给它添加 deposit和 withDraw 两个⽅法。最后再给 model 类定义⼀个事件,该 event ⽤来通知外界余额变了,

它通常⽤来提醒 View 更新⾃⼰的显⽰。所以综合起来,Model 类看上去是这样的:

classdef Model < handleproperties

balanceendevents

balanceChangedendmethods

function obj = Model(balance)obj.balance = balance;

endfunction deposit(obj,val)

obj.balance = obj.balance + val;obj.notify('balanceChanged');

endfunction withDraw(obj,val)

obj.balance = obj.balance - val;obj.notify('balanceChanged');

endend

end

30 MATLAB 中⽂论坛技术专栏

1.5.3 用 App Designer 布局 View参照教程 1,⽤ App Design 设计布局得到的效果如下:

图 1.28

我们的最终⽬的是得到 App Designer ⽣成的, 对应这个布局的⾯向对象的代码,这可以

通过点击 Code View 然后把代码拷贝出来得到,具体操作见教材 1 和教材 2。得到⾯向对象的代码之后,我们还需要做如下的⼯作:• 为了让代码更易读懂,改变了⼀些属性的名字,让它们变得更有易读,对应注释 (1)

部分

• 按照 MVC 模式,View 类必须拥有 Controller 和 Model 的对象 handle, 我们给 View添加两个属性,分别是 controlObj, 和 modelObj,对应注释 (2)

• View 对象将负责产⽣⾃⼰的 controller 对象,并且给⾃⼰的控件注册回调函数,这

对应 startupFcn 中的注释 (3) 部分

• 添加⼀个 updateBalance ⽅法,监听 model 的 balanceChanged 事件,对应注释 (4),它⽤来刷新 View 的显⽰

classdef View < matlab.apps.AppBase

% Properties that correspond to app componentsproperties (Access = public)

UIFigure matlab.ui.Figure % UI FigureLabelNumericEditField matlab.ui.control.Label % BalanceviewBalance matlab.ui.control.NumericEditField % (1)LabelNumericEditField2 matlab.ui.control.Label % RMBviewRMB matlab.ui.control.NumericEditField % (1)DepositButton matlab.ui.control.Button % (1)WithDrawButton matlab.ui.control.Button % (1)

controlObj % (2)

MATLAB App Designer 教程 31

modelObj % (2)end

methods (Access = private)function startupFcn(app)

app.controlObj = Controller(app,app.modelObj); % (3)app.attatchToController(app.controlObj); % (3)

app.modelObj.addlistener('balanceChanged',[email protected]); % (4)

endend

...

接下来:

• 我们要实现 attachToController ⽅法,就是给两个按钮注册 ButtonPushed 回调函

数,对应注释 (5), 按照 MVC 的规定,这些回调函数来⾃于 controller• 修改 View 的 constructor, 接受⼀个 model 对象做为参数,并且在内部⽤属性 mod-

elobj 保存下来,其余不变, 对应注释 (6)• 最后实现 updateBalance 函数, 直接从 model 出取得 balance 的值,更新⾃⼰的属性

(显⽰), 对应注释 (7)

% App initialization and constructionmethods (Access = private)

function attatchToController(obj,controller) % (5)funcH = @controller.callback_withDrawButton;addlistener(obj.WithDrawButton,'ButtonPushed',funcH)

funcH = @controller.callback_depositButton;addlistener(obj.DepositButton,'ButtonPushed',funcH)

end

% Create UIFigure and componentsfunction createComponents(app)

% ... createComponents 方法不变

end

32 MATLAB 中⽂论坛技术专栏

end

methods (Access = public)

function app = View(modelObj) % (6)app.modelObj = modelObj; % (6)createComponents(app)registerApp(app, app.UIFigure)runStartupFcn(app, @startupFcn)

% register callbackif nargout == 0

clear append

end

function updateBalance(obj,src,data) % [7]obj.viewBalance.Value = obj.modelObj.balance;

end

% ...

endend

图 1.29

MATLAB App Designer 教程 33

1.5.4 给 View 添加 Controller最后⼀个步骤是通过 controller 把 Model 和 View 联系起来. 类定义如下. 主要功能是

把⽤户对界⾯上的按钮的点击,转换成对 model 类的 withDraw 和 deposit ⽅法的调⽤。

classdef Controller < handleproperties

viewObj;modelObj;

endmethods

function obj = Controller(viewObj,modelObj)obj.viewObj = viewObj;obj.modelObj = modelObj;

endfunction callback_withDrawButton(obj,src,event)

obj.modelObj.withDraw(obj.viewObj.viewRMB.Value);endfunction callback_depositButton(obj,src,event)

obj.modelObj.deposit(obj.viewObj.viewRMB.Value);end

endend

1.5.5 启动 MVC最后我们需要⼀个脚本,按顺序的初始化各个 MVC 的对象,来启动这个 GUI:

modelObj = Model(800);viewObj = View(modelObj);

注意我们⾸先声明的 Model 对象,账户余额 800。然后再把它当做 iew 对象构造函数的输

⼊,在 View 对象的内部,⽣成了 Controller 对象。

1.5.6 App Designer + MVC 流程回顾这⾥再回顾⼀下为什么要使⽤ App Designer 来布局。在有 App Designer 之前,⽤户可

以通过 GUIDE 布局,得到的⾮⾯向对象的代码,这样的代码和 MVC 模式⼏乎没有任何的

兼容性,也就是说,GUIDE 和⾯向对象的 MVC 模式⽆法同时使⽤,GUIDE 不适⽤于中型

⼤型规模的 GUI 设计。

在 MATLAB ⾯向对象编程-从⼊门到设计模式中,我从如何程序化的构造 GUI 出发,

介绍了 MVC 模式,并且提出,在⾯向对象 GUI 编程中,可以使⽤ GUI Layout Manager 来

34 MATLAB 中⽂论坛技术专栏

程序化的布局。读者可以把 GUI Layout Manager 想象成⼀个透明的 GUI 框架,视觉上 GUILayout 提供的容器不会在最终的 GUI 上有任何的效果,⼀旦我们定义出了这个透明的框架,

它帮我们⾃动摆放所有控件。但这个⽅法我们仍然需要⾃⼰定义 GUI Layout Manager 中的

各种容器,并且指定它们之间的包含关系。如下

图 1.30

现在有了 App Designer, 搭建 GUI 框架的⼯作也就可以省下来了,并且我们可以更加

⾃由的摆放和对齐控件,设置控件的⼤⼩,设计完毕之后,通过 Code View 直接把代码拷贝

出来就得到到了 View 类的基本定义了,这是 GUI 设计⼯作流程中很⼤的⼀个进步。

MATLAB App Designer 教程 35

1.6 从 App Designer 的局限性谈 MATLAB 的图形系统(本篇内容均来⾃⽹络中的公开内容)在 App Designer(下⾯简称 AD)连载的第⼀篇中,

zhuanlan.zhihu.com/p/20821503?refer=matlab

就有读者留⾔提到 AD 找不到控件表格,⽣成的界⾯没有菜单。如果观察 AD 的左边⼯具

栏,可以发现其中列出的对图形系统的⽀持中,确实没有表格控件,在 Design View 的画板

上,确实也没有以往我们熟悉的顶上的菜单栏。其实在 Mathworks 的⽂档中,已经清楚的

提到 AD 对图形系统的⽀持。

www.mathworks.com/help/matlab/creating_guis/graphics-support-in-app-designer.html

⽐如在 R2016a 的版本中,在 AD 的坐标轴中,我们可以使⽤ line,text, scatter 等功能,

到了 R2016b,我们可以在 AD 的坐标轴中使⽤更多的图形对象, 但是,这还远不是 MATLAB图形系统的全部内容,这就是说在 AD 只⽀持了部分的图形系统。

图 1.31

那么我们该怎么理解“App Designer 对 MATLAB 图形系统的⽀持”这句话呢,App De-signer 难道不是 MATLAB 图形系统的⼀部分吗?要回答这个问题,我们先观察 AD ⽣成的

36 MATLAB 中⽂论坛技术专栏

代码中的这么⼀段

图 1.32

这是 AD ⽣产的⾯向对象代码中产⽣界⾯的代码,和我们熟知的 figure 不同,AD 中使

⽤ uifigure 这个命令产⽣界⾯。我们可以在命令⾏中看看这两个命令有什么不同:

>> f1 = figuref1 =Figure (1) with properties:

Number: 1Name: ''

Color: [0.9400 0.9400 0.9400]Position: [680 558 560 420]

Units: 'pixels'Show all properties

>> class(f1)ans =matlab.ui.Figure % 返回的对象是 matlab.ui.Figure 类

>> f2 = uifiguref2 =Figure with properties:

Number: []Name: ''

Color: [0.9400 0.9400 0.9400]Position: [680 558 560 420]

MATLAB App Designer 教程 37

Units: 'pixels'

Show all properties

>> class(f2)ans =matlab.ui.Figure % 返回的对象是 matlab.ui.Figure 类

它们返回的都是 matlab.ui.Figure 对象,但是产⽣的界⾯ (Figure) 确具有不同的外观,⽐如

⼀个有⼯具栏,⼀个没有⼯具栏。

图 1.33

理解它们的区别,我们需要分清楚图形对象,和图形对象的绘制 (rending) 这两个概

念。figure 和 uifigure 命令都返回同⼀个类的图形对象,但是 MATLAB 如何对该图形对象

的绘制确⽤了完全不同的机制。当使⽤ figure 命令时,MATLAB 在 JFrame 上绘制 JavaSwing 对象,⽽当使⽤ uifigure 的时候,MATLAB 其实是在⼀个缩减版的 Web Browser 上

⽤ JavaScript 的 DOJO 在画图,这就是 AD 的最⼤不同,我们看到的界⾯,其实是⼀个嵌

⼊式的 Chromium(Chromium Embedded Framework)。

图 1.34

注意,图中的双箭头表⽰,绘制完成的图像还⽀持和 MATLAB 图形系统的互动,这意

味⽤户和图像的互动,所可能产⽣的结果,也会反应到 MATLAB 内部的图形对象中。

38 MATLAB 中⽂论坛技术专栏

现在我们可以理解什么叫做”App Designer 对图形系统的⽀持” 了,MATLAB 的图形

系统是 MATLAB 内部最⼤最复杂的⼀个⾯向对象的系统,该图形系统负责产⽣维护图形对

象,⽐如

>> l1 = linel1 =Line with properties:

Color: [0 0 0]LineStyle: '-'LineWidth: 0.5000

Marker: 'none'MarkerSize: 6

MarkerFaceColor: 'none'XData: [0 1]YData: [0 1]ZData: [1x0 double]

所有返回的对象都有⼀个正式的在对象系统中的名字, 可以通过 class ⽅法来查看

>> class(l1)ans =matlab.graphics.primitive.Line

该类的名字叫做 Line ,它属于 matlab.graphics.primitive Package。⽽ line 本⾝只是⼀个函

数,它返回⼀个 matlab.graphics.primitive.Line 对象。

⽽把该对象在 Web Browser 上绘制出来,MATLAB 还要去使⽤ DOJO 的 library,所

谓的 AD 对 MATLAB 图像系统的” ⽀持”,就是 AD 能否 (还有没有) 把庞⼤的 MATLAB图形对象系统中的所有图形和功能都在 Web Browser 上画出来, ⽬前来说,还没有完全做

到。我们在前⽂的表中也看到了,但这样的对应,从 AD 推出以来,正在迅速的增加。在

Web Browser 上绘制 MATLAB 图像对象(事实上 MATLAB online 的所有图像都是 WebBased),对数据的可视化展开了⼀扇⼤门,所以我们应该满怀期待!

说到 line 返回⼀个 MATLAB 图形对象,MATLAB 的⽼⽤户⼀定都还记得 R2014b 以

前,所有图形系统的命令返回的都是⼀个 double

% Before R2014b>> l = linel =

9.765625000000000e-04

MATLAB App Designer 教程 39

但是,我们仍然可以⽤这个 double handle 来查询该 line 对象的属性

>> get(l)DisplayName =Annotation = [ (1 by 1) hg.Annotation array]Color = [0 0 0]

.....

这是因为 MATLAB 图形系统在历史上有两个主要的版本,⼀个是 R2014b 以前的版本,⼀

个是 R2014b 之后的版本,R2014b 之后的图形系统是⾯向对象的图像系统,是较 R2014b以前的图形系统⼀个全新的升级。⾄于 R2014b 以前的版本我们就不介绍了,如果你还在⽤,

该升级你的 MATLAB 啦!

作者简介

徐潇

MathWorks 开发部 MATLAB 架构 C++ ⾼级软件⼯程师。计算物理学博⼠,研究⽅

向为电⼦结构计算、密度泛函算法开发;计算机硕⼠,研究⽅向为图像处理。2004 年,开始

使⽤ MATLAB,在科研编程中遇到了开发⼤型程序难以维护的困难,花了很多时间⽤于改

进程序但效果总不尽如⼈意。2009 年,开始使⽤ MATLAB ⾯向对象编程,发现⼯程进度被

迅速加快,于是萌⽣了写⼀本介绍 MATLAB ⾯向对象编程书的念头, 这就是 «MATLAB面向对象设计编程:从入门到设计模式 » 的起源。2011 年,在美国取得博⼠学位之后⼊职

MathWorks,从理科科研⼯作者和多年的 MATLAB 爱好者,成为⼀名 MATLAB 语⾔的

设计开发和实现的软件⼯程师。2016 年,作者在 MATLAB 中⽂论坛开辟了技术专栏,和

⼤家分享最新的⾏业应⽤技术和 MATLAB 编程理念,旨在推动软件⼯程中的现代⼿段在

MATLAB 科学⼯程计算项⽬中的使⽤,帮助科学家和⼯程师们更有效地解决复杂的科研问

题。«MATLAB ⾯向对象设计编程:从⼊门到设计模式 » 凝结了作者多年的科研和⼯作经

验以及对 MATLAB 语⾔的理解,希望能对各种规模的科学⼯程计算项⽬的 MATLAB 使⽤

者有所启发。

40

更多 MATLAB 中文论坛技术文章

(1) MATLAB 性能测试框架

(2) 物联⽹专题——Internet of Things• Thingspeak 能为我们做什么

• 如何⽤ Browser 向 Thingspeak 推送数据

• 如何⽤ Postman 向 Thingspeak 获取和推送数据

• 如何在 Thingspeak 中添加 MATLAB Plot• 如何使⽤ Javascript 获得 Thingspeak 频道数据

• 如何在 Thingspeak 中使⽤ JS Plugin• NodeMCU 基础篇

• NodeMCU 和 Thingspeak• 如⽤ Thingspeak 和 IFTTT 让物联⽹硬件发邮件

• 如何⽤ Thingspeak 控制联⽹的硬件

(3) MATLAB 中⽂论坛常见问题归纳

(4) 为什么要基于模型设计?

(5) MATLAB 单元测试

(6) 对函数的输⼊进⾏检查和解析

(7) MATLAB 映射表数据结构

(8) MATLAB table 数据结构

(9) ...

41