最近也是在研究MATLAB App Designer,开这样的一个系列主要是为了记录我在研究App Designer时遇到的一部分问题的解决,和一部分有趣的想法,每一篇文章会展示如何将一个项目mlapp化。
mlapp化的大部分都是以前做的小项目,因此各个组件的属性便可以直接复制,这一部分不详细解说,以下是将像素化程序使用App Designer编写过程中可能会遇到的问题。

入门实战第一弹——像素画绘制App


目录

  • 1.如何在App启动时,让坐标区显示图像
  • 2.如何在App启动时,为变量赋值,如何设置全局变量。
  • 3.如何创建和使用函数
  • 4.如何判读鼠标是否点击坐标区,如何获得鼠标在坐标区内位置
  • 5.如何在同一坐标区绘制多个图像
  • 6.如何不显示UIAxes的工具栏


1.如何在App启动时,让坐标区显示图像

如图所示,程序刚启动红框的位置内就已经有一个调色板,

appdesigner pannel中显示子界面_实战


如果在App Designer内编程,这个图片我们在这个坐标区域自动创建的时候没办法加一个这样的图像,因为:

灰色区域无法手动修改

appdesigner pannel中显示子界面_入门_02


属性检查器没有添加图像的属性

appdesigner pannel中显示子界面_MATLAB_03

这时候就需要我们的startupFcn回调函数,这个函数是,在所有自动创建元件创建完后会自动调用一次,创建方法为:


appdesigner pannel中显示子界面_实战_04


appdesigner pannel中显示子界面_App Designer_05

之后便可以使用imshow plot scatter等函数在startupFcn回调函数内为特定坐标区域绘制图像,这些函数对于UIAxes的使用方法详见Mathworks,这里列举一部分:

plot:
plot(app.UIAxes,X,Y)
imshow:
imshow(Pic,‘Parent’,app.UIAxes)

2.如何在App启动时,为变量赋值,如何设置全局变量。

要在App启动时为某些变量设置初值,依旧需要用到startupFcn回调函数,比如我希望程序一开始,初始颜色为蓝色,就可以:

appdesigner pannel中显示子界面_实战_06


但如果像图中这样直接设置数值,只能在startupFcn一个函数内使用,也就是说他是一个局部变量,无法跨函数使用,我们是想设置一个初值,如果设置了之后其他函数不能用那肯定不行,这时候我们需要给app添加属性,具体方法如下:

appdesigner pannel中显示子界面_App Designer_07

通过点击上面两个按钮我们发现,此时代码部分多了几行:

appdesigner pannel中显示子界面_入门_08


这里的Property只是一个示例,完全可以改成其他名字:

appdesigner pannel中显示子界面_MATLAB_09


这时候我们再看之前startupFcn内的代码提示:

appdesigner pannel中显示子界面_App Designer_10


使用app.presentColor引用此属性,这时候在程序的任何地方都可以通过app.presentColor改变取值或者调用,例如(赋值):

appdesigner pannel中显示子界面_像素画_11


分析

我对app以及其属性的理解是,这里面这个小写的app,在每个函数都会被作为参数传入,有点类似python中的this,我们可以为其增添属性,既然app在每个函数内都能引用,那么其属性的使用过程有点类似与全局变量的使用。

多个属性创建:

通过换行分隔创建多个属性:

appdesigner pannel中显示子界面_像素画_12


通过’,‘及’;'分隔创建多个变量

appdesigner pannel中显示子界面_App Designer_13

3.如何创建和使用函数

像素画程序涉及到了十六进制码向RGB颜色的转换,我们因此需要创建互相转化用到的相应函数,创建方法如下:


appdesigner pannel中显示子界面_像素画_14

通过此方法创建的函数具有以下的形式,其中的函数名,输入输出都是可以更改的:

appdesigner pannel中显示子界面_像素画_15


需要注意的是,函数可以有多个参数,但是第一个参数必须是app,如果在函数中没有使用到app这个参数,则可以使用~来替换,如下图所示:

appdesigner pannel中显示子界面_MATLAB_16


另外编写的函数在调用时,无论函数是否使用到app这个参数,无论是否使用~,app都必须作为输入参数,如下图所示,该函数使用时的第一个参数为app。

appdesigner pannel中显示子界面_像素画_17

4.如何判读鼠标是否点击坐标区,如何获得鼠标在坐标区内位置

首先UIAxes是无法添加回调的,要判断鼠标是否点击坐标区,需要使用UIFigure所带的WindowButtonDownFcn回调函数,该函数的创建方式与之前提到的startupFcn回调函数相同,且回调函数会在鼠标点击程序界面时被调用,需要注意的是,UIFigure还有一个回调名为ButtonDownFcn,这两个函数是有一定差别的,对于WindowButtonDownFcn回调函数,界面上的任意点击都会调用该函数,但对于ButtonDownFcn函数来说,鼠标只要无法直接点击到UIfigure都无法调用该函数,

作用范围:

红框以内,蓝框以外

WindowButtonDownFcn:

appdesigner pannel中显示子界面_入门_18

ButtonDownFcn:

appdesigner pannel中显示子界面_实战_19


设置了WindowButtonDownFcn回调之后我们可以通过UIFigure自带的CurrentPoint属性获取鼠标最后点击的点相对于UIFigure坐标体系的位置,在通过和UIAxes位置进行比对后,确定鼠标点击点是否在UIAxes内,在哪个UIAxes内,同时UIAxes也有CurrentPoint属性,可以获得相对于UIAxes鼠标最后点击点的位置。

appdesigner pannel中显示子界面_实战_20


这里图方便用了switch函数,看不懂这个操作的可以老老实实的用if来写分支。

注:

在较新的版本中可以通过 获取uifigure的CurrentAxes属性来得到最后点击的uiaxes,只需要将代码改为(后面会提到这里为啥只用了x坐标):

appdesigner pannel中显示子界面_入门_21


这里uifigure的名字比较长不太好看,但重点是后面的CurrentAxes属性,他就是最后点击的uiaxes,具有着AXES所具有的所有属性,因此我们当然可以依据tag来区分uiaxes:

appdesigner pannel中显示子界面_实战_22


但其实各个uiaxes还有一个明显的区分就是其Position位置属性,不同做坐标区域位置是不同的,由于我们这个程序就俩uiaxes控件而且x坐标还不一样,因此我们可以只判断tempAxes的Position属性的第一个数值来判断,当然若是控件出现c轴坐标相同的情况,就需要把y轴坐标一起纳入考虑。

5.如何在同一坐标区绘制多个图像

UIAxes中绘制图像时一般会自动刷新之前的图像,想要灵活的绘制多个图像可以使用hold函数,具体使用方式参见官网,这里只介绍基础使用方法。如图所示,使用方法类似之前的hold on,hold off,不过需要对特定的UIAxes使用。

appdesigner pannel中显示子界面_实战_23

6.如何不显示UIAxes的工具栏

程序中,左侧的坐标区域是有工具栏的,但是右侧的坐标区的工具栏是被隐藏的,为的是防止工具栏妨碍取色:

appdesigner pannel中显示子界面_App Designer_24

这个设置可以在startupFcn内设置,如图所示:

appdesigner pannel中显示子界面_MATLAB_25


可以通过

app.UIAxes.Toolbar.Visible=‘off’

这样的方式,对其进行隐藏