1.5 MATLAB App Designer 和 MVC · 2019-01-21 · MATLABAppDesigner教程 27 1.5 MATLAB App...
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