6.写在前面
我要特别感谢一下CSDN这个技术平台,在昨天我发布了我的第一篇blog ,就被平台推流,而且今天早晨收到此篇blog 进入【CSDN每天最佳新人】榜单的消息,欣喜若狂,受宠若惊。感到平台对新人作者和原创文章的无限尊重与无穷善意,我想这也是各领域的能人异士,乐于在本平台分享知识、交流心得的原因吧!也衷心祝愿本平台越来越好(词穷但认真)!
本篇blog 直接从chap 6 开始写了,此次【连载爽文 Part.2】书接上回,因为本人语言能力有限,代码也不尽如人意,所以昨日拖拖拉拉只完成了App Designer 准备工作的一部分,但已经4000+ characters 。担心文字冗长乏味,使各位看官老爷觉得枯燥无趣,只略施小计,讪讪在文章标题前加了这么个噱头。再行连载本篇是为了与诸位共同探讨学习app designer 的基本使用技法和思路,也是一例简单的Matlab 应用程序的实践。(下图取自我发表的第一篇blog )
7. App Designer 的样板设计
样板设计就是应用程序的交互排布了,我将app分为了显示区、交互按钮区和puzzle 解谜区3个区域,基本样板如图(显示区为左上、交互按钮区为左下、puzzle 解谜区在右侧):(该图是puzzle 完全开发后初次启动运行的样子(只交互了该puzzle 的startupFcn ))
上图可知。我们制作了四个功能按钮,分别为START ,CHECK ,SHOW ,&RESET 。
START:通过对函数F(在上篇有介绍),随机出一个新的puzzle至右侧解谜区。
CHECK:检测解谜区的puzzle 完成情况,并且输出您完成该puzzle 的步数(此值在闭区间[4,16]之内)这两段输出文档将生成在左上方的显示区中。
SHOW:将START 键产生的puzzle a 完全展示在解谜区,并以二进制4*4 矩阵的形式将答案输出于显示区。
RESET:完成一次puzzle 后按下,会将右侧解谜区完全清除(呈上图的样子)。说直白点呢,就是相当于关闭游戏,又重新打开了一下。
解谜区如何交互呢?因为信号灯Lamp(上图16圆)没有交互属性(中国话就是说,这个灯灯它点不了)所以在16 个信号灯Lamps 下面(注意设置图层关系)又藏了16个按钮Buttons以控制信号灯的颜色,交互之后可以改变Lamp 的颜色(答案正确变绿,答案错误变红)。
反思:其实这里可以用组件库的【图像】组件,可以更完美且更便捷地模拟本篇开始的图片那样——点击图案→正确则显示彩色图像块,错误则显示黑白色的图像块。这种方法且不说虽需要制作2*4*4,两套图像(一套正确彩色,一套错误黑白)和初始图像1*4*4个问号吧(假设)。共制作33张大小统一的图片。但是它快啊(因为它善),交互起来很舒服。
不说这么多,意思就是:我太懒了我不想干你们来吧。
8.显示区
我很笨很懒,图示的标签显示因为要多次换行,所以我拖入了3个固定标签,以及3个变量标签。稍加排版(这里有【*山代码】之嫌,且虚心求教!不在话下。)
*3个固定标签即是这三张
从左至右依次服务于 START&RESET(共用图例1)、SHOW、CHECK。
这三个标签的内容是固定的(即【.Text 】的解析不随交互而变化)只需要改变这三个组件的【.Visible 】解析属性,即可完成按钮和显示区内容的切换。
——这操作简直是拯救人(猪)脑的不二法门。
*3个变量标签即是这三张
初值为YroN 的标签用以表示判定puzzle 完成情况;
初值为Times 的标签以表示步数;
初始DO NOT EXIST 标签以展示puzzle 的整体分布。
在chap7有提到过这些标签与按钮区的交互方式!不再赘述咯。
9.解谜区的交互方式 以及 前置脚本!
我制作了交互解谜区16按钮的方式
以及五个.mlx 脚本,脚本分别命名为Wre、Sow、Cln、Able、dAble。
名称呢,分别取自英文Where、Show、Clean、Able、disAble。接下来为大家介绍用途:
9.1 解谜区的交互
此脚本用以查找每次按键之后,我们到底按在哪里了?按下的答案对不对。
解谜区的交互我直接写到app designer 里面区了,因为很简短,但是调用的组件名称又不能标准化。所以也是开开心心写了16份相似的代码(只有调用名称有所差异)。蛮整齐的嘞~
a=evalin('base','a');
if a(1)==1
app.a_1.Color='g';
else
app.a_1.Color='r';
end
t=evalin('base','t');
t(1)=1;
assignin('base','t',t)
app.Button_1.Enable=0;
注意看,这个app.a_1 是第一个灯泡(此后的灯泡按4*4方阵的元素位置排列,分别是a_1、a_2...a_16)当你按下解谜区第一行第一列的button,就会开始判断我们生成的puzzle棋盘的第一个元素a(1)是否为1,1返还Color='g',0返还Color='r'。我们有必要解释一下这个t,因为这个t是在交互START按钮后生成的,用以记录我们按下按钮的位置。
app.Button_1.Enable=0; 库库破釜沉舟,按完这个按钮就不让你再按了。
9.2 Wre.mlx
此脚本以define puzzle 是否完成;
并且定位完成的通路位置;
e=zeros(4);
for n=1:16
if t(n)==1
e(n)=a(n);
end
end
cross=[sum(diag(e)),sum(diag(flipud(e)))];
col=sum(e); % only col(1)==4
row=sum(e,2)';
mix=[cross,col,row]; % mix 是一个1*10的列表
得到s;
当没有通路时,s=0;
当有通路时,s的值是通路的位置;
s=find(mix==4);
def=size(s);def=def(2);
if def==0
s=0;
end
将位置参数转化为字符串str;
if s==0
str='The puzzle is not finished';
elseif s==1
str='main diagonal';
elseif s==2
str='sub diagonal';
end
if s>2 && s<=6
str=['Puzzle done with column ',num2str(s-2)];
end
if s>6 && s<=10
str=['Puzzle done with row ',num2str(s-6)];
end
9.3 Sow.mlx
此脚本以展示底层puzzle ;
傻瓜代码,只展示一部分,第1列 lamp 展示;
if a(1)==1
app.a_1.Color='g';
else
app.a_1.Color='r';
end
if a(2)==1
app.a_2.Color='g';
else
app.a_2.Color='r';
end
if a(3)==1
app.a_3.Color='g';
else
app.a_3.Color='r';
end
if a(4)==1
app.a_4.Color='g';
else
app.a_4.Color='r';
end
毫无技巧可言。可以讨论
9.4 Cln.mlx
此脚本以将所有的Lamp复原至灰色;
下为部分代码:(同样为第一列)
app.a_1.Color=[0.80,0.80,0.80];
app.a_2.Color=[0.80,0.80,0.80];
app.a_3.Color=[0.80,0.80,0.80];
app.a_4.Color=[0.80,0.80,0.80];
9.5 Able.mlx & dAble.mlx
此脚本以改变按钮button的交互性质。
顾名思义,前者使button 可交互,后者将button 变不可交互(分别为下方上、下两条代码)。
app.Button_1.Enable=0;
app.Button_1.Enable=1;
10.startupFcn 以及 按钮交互区的回调!
终于来到了自认为很关键的部分,至此上文已经达到1500+字数了~本章会为大家介绍四个按钮的功能以及源代码!
10.1 startupFcn回调
直接展示可编辑段:
evalin('base','clear variables')
dAble
app.START.Enable=1;
app.RESETButton.Enable=0;
app.SHOWButton.Enable=0;
app.CHECKButton.Enable=0;
此时为应用刚打开的情形(参考样板设计图例),
所有的解谜区按钮不可交互,
START按钮可以交互,RESET、SHOW、CHECK按钮则无法选中(可以躲元气弹了)。
10.2 START 按钮回调
app.start.Visible=1;
app.check.Visible=0;
app.YorN.Visible=0;
app.Times.Visible=0;
app.show.Visible=0;
app.atext.Visible=0;
app.START.Enable=1;
app.RESETButton.Enable=1;
app.SHOWButton.Enable=1;
app.CHECKButton.Enable=1;
Cln
Able
F
assignin('base','a',a)
t=zeros(4);
assignin('base','t',t)
第一部分为标签的可视化,交互之后只能看到第一段文字(显示区的第一固定标签)
第二部分为按钮去的可交互调用,此时什么都可以按了。
第三部分先是Cln 将所有的Lamp复原至灰色,然后使Lamp 下的Button 可交互了。
再运行函数F(上篇内容),将a写入工作区,建立全0矩阵t,写入工作区。
assignin 函数和evalin 函数是非常重要的,否则会出现没有写入的情况,
(一般写入和调用同时存在,逻辑为:写入——调用——工作区的数据处理——再写入)。
10.3 CHECK 按钮回调
app.start.Visible=0;
app.check.Visible=1;
app.YorN.Visible=1;
app.Times.Visible=1;
app.show.Visible=0;
app.atext.Visible=0;
app.START.Enable=1;
app.RESETButton.Enable=1;
app.SHOWButton.Enable=1;
app.CHECKButton.Enable=1;
a=evalin('base','a');
t=evalin('base','t');
Wre
assignin('base','a',a)
%assignin('base','str',str)
app.YorN.Text=str;
t=sum(sum(t));
app.Times.Text=num2str(t);
第一二部分同样是对【标签可视化】和【按钮交互性】的定义,乖的宝宝已经可以自行理解了。
第三部分即是 assignin 函数和evalin 函数的一个英语,因为Wre 脚本会用到a,我们需要先行调用(此部分虽然没有对a进行任何处理改动,但为了美观和杜绝软错误,我们还是再写入了)
注意app.YorN.Text=str;其代码意义就是将YorN 这段标签的Text 内容改为str ,str 的定义在Wre.mlx 中有提到,动动小手指向上翻翻看吧~
这个t则是我们和解谜区按钮交互的位置,通过sum(sum()) 两次求和,生成t(times) 用于度量次数,值得注意的是.Text的解析只能被【字符串类型】赋值,甚至字符串构成的向量或矩阵,都无法用于改变标签的内容。
10.4 SHOW 按钮回调
app.start.Visible=0;
app.check.Visible=0;
app.YorN.Visible=0;
app.Times.Visible=0;
app.show.Visible=1;
app.atext.Visible=1;
app.START.Enable=1;
app.RESETButton.Enable=1;
app.SHOWButton.Enable=1;
app.CHECKButton.Enable=0;
dAble
a=evalin('base','a');
Sow
assignin('base','a',a)
app.atext.Text=strcat(num2str(a(1,:)),10,num2str(a(2,:)),10,num2str(a(3,:)),10,num2str(a(4,:)));
t=zeros(4);
assignin('base','t',t)
一二部分跳过
SHOW按钮按了之后,解谜区就不可用了。这里又有一个小技巧,就是如何让app 的标签组件进行分行输出(对,没错,就是那条最长的):
app.atext.Text=strcat(num2str(a(1,:)),10,num2str(a(2,:)),10,num2str(a(3,:)),10,num2str(a(4,:)));
就是按照a的四行,每行转为字符串,然后分段输出。
哇,真的是太神奇辣~(章鱼哥音)
——虽然试了很久如何分段输出:所以不是我笨,我真的只是懒。
10.5 RESET 按钮回调
app.start.Visible=1;
app.check.Visible=0;
app.YorN.Visible=0;
app.Times.Visible=0;
app.show.Visible=0;
app.atext.Visible=0;
evalin('base','clear variables')
dAble
Cln
app.START.Enable=1;
app.RESETButton.Enable=0;
app.SHOWButton.Enable=0;
app.CHECKButton.Enable=0;
样板设计的时候已经介绍过RESET 按钮了,就是将应用程序初始化一下。
(结束了罪恶的一生,然后开始了罪恶的下一生。)
11. Last 写到最后
本篇插入的Matlab 代码段,除了chap 9 的五个脚本都是App Designer 的可编辑部分!
果然不出所料,写这篇blog的时候出现了闭环。因为当我想要介绍前置脚本Wre.mlx 的时候,就一定会提到如何交互解谜区的16按钮,要介绍如何通过按按钮来进行答案监测,又需要写出START 按钮的初始赋值情况,当我决定先写START按钮的回调时,又发现按钮里包含了前置脚本。嚯嚯嚯,所以就按我们(我自己)最能理解的地方开始解释咯~
本次的蓝色部分仍然为讨论部分,手机版可能看不到,认准【可以讨论】字样。
此次连载新增了红色部分,是我觉得写App Designer 时很重要的技巧,也供讨论,畅所欲言。
各功能按钮会导致有一些按钮不能用,这里只tip 上了源代码而不能尽其言。是我的失职,如果想玩一下的话,我可以打包发给你们u~
作者本科在读,但非计算机及相关专业的学生。所以觉得对互联网时代的普遍认知以及观念还不能尽然,代码风格可能遭人唾弃(虚心接受)。但我相信检验出真理这句话。唯有实践才能回溯性的构建思想,解放思想,推陈出新。
本篇也是作者第一次编写APP designer 并且第一次在CSDN发布blog,一路写来,还是有很多大家可以用的上的思路和技巧(是我自己这么想)总之谢谢大家的喜欢!
💐完结撒花
这个puzzle 的爽文至此结束了!再次感谢一下CSDN和CSDN平台上勤奋的IT小猴子们~
希望和大家一起思考,多多讨论。