App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网

第3课 编写程序——处理按钮点击事件

1、流程图

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 18 按钮点击事件引发的处理流程
图1- 18中的流程有三种可能的路径:如果点击按钮翻开的的是第一张卡片,则执行路径①——记住第一张卡片;如果点击按钮翻开的是第二张卡片,则记住第二张卡片,并判断两张卡片图案的异同,如果相同,则执行路径②,否则,执行路径③;无论是执行路径②或路径③,最后到要忘记两张卡片。

注意流程图中的三个矩形框:记住第一张卡片、记住第二张卡片、忘记两张卡片,这是编写程序的关键。所谓记住或忘记,就是要用全局变量来记录已经翻开的卡片。这里我们声明两个全局变量:翻牌1及翻牌2,来保存正在翻开等待判断的两个按钮对象。在应用初始化时,设置它们的值为0 ,当第一张牌被翻开时,设

翻牌1 = 第一个被点击的按钮对象

当第二张牌被翻开时,设

翻牌2 = 第二个被点击的按钮对象

并以这两个变量为依据,判断按钮图案的异同。

2、判断两个按钮图案的异同

我们先以按钮1及按钮2为例来编写代码,如图1- 19所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 19 以按钮1及按钮2为例编写的点击事件处理程序
当按钮1或按钮2被点击时,事件处理程序的执行过程如下:

  1. 根据按钮对象在按钮列表中的位置(索引值),从随机图案列表中获取按钮的正面图案,并显示该图案;
  2. 设置被点击按钮的启用属性值为假(考虑一下为什么,如果不这样,当再次点击该按钮时,会发生什么事情?);
  3. 判断它是不是第一张被翻开的卡片,如果是,将翻牌1设置为该按钮对象,否则,将翻牌2设置为该按钮对象,并判断已经翻开的两个按钮的正面图案是否相同。这里我们暂时不做进一步的处理,而是利用屏幕的标题属性来显示测试结果,即,如果按钮1与按钮2的图案相同,则屏幕的标题显示“图案相同”,否则显示“图案不同”;
  4. 如果已经翻开两张卡片,无论它们的正面图案是否相同,都必须重新将翻牌1及翻牌2的值设置为0。

测试结果如图1- 20所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 20 对上述代码的测试结果

3、处理两个按钮图案相同的情况

按照图1- 18的设计,当图案相同时,记住已经翻开的卡片对数。凡是需要记住的内容,都需要一个全局变量来保存它,已翻开卡片的对数一方面用于计算游戏得分,另一方面用于判断是否所有卡片都已经被翻开(等于8时)。我们将这个变量命名为翻牌对数。

当两张卡片的正面图案相同时,有三件事情需要完成:

  1. 为全局变量翻牌对数的值+1;
  2. 计算并显示游戏得分;
  3. 判断翻牌对数是否等于8,并依据判断结果选择执行两条路径之中的一条:
    • 当翻牌对数=8时,显示“游戏结束”;或者
    • 当翻牌对数<8时,显示“图案相同”。

假设每翻开一对卡片得10分,因此游戏得分 = 翻牌对数X10,我们用标签得分来显示游戏得分,具体代码如图1-21所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 21 当两张卡片图案相同时,显示分数,如果翻牌对数=8,则游戏结束

4、处理两个按钮图案不同的情况

当两张被翻开的卡片图案不同时,将它们重新扣上,即,让它们显示背面图案。为了让已经翻开的图片能够显示一定的时间,这里需要用到计时器组件,一旦判断出两个卡片图案不同,则启动计时器,经过一个计时间隔的时长后,计时器发生计时事件,在计时事件的处理程序中,将两张卡片同时扣上。我们用闪现计时器来实现这一功能。这里闪现计时器的计时间隔为500毫秒,如果需要加大游戏的难度,可以将计时间隔设置的更短。

我们在“图案不同”的分支里添加一个语句——启动闪现计时器,并编写了闪现计时器的计时事件处理程序,如图1- 22所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 22 当两张卡片图案不同时,启动闪现计时器
在闪现计时器的计时事件中,我们设置两个按钮的启用属性为真,图像属性为背面图案,并将计时器1的启用属性设置为假,即,让计时器1停止计时。经过测试,程序运行正常。

5、代码的复用——改进按钮点击事件处理程序

到目前为止,我们已经能够处理两个按钮的点击事件,我们需要将按钮1点击事件处理程序中的代码复制到其他14个按钮的点击事件处理程序中。这种说法听起来很可怕,试想,如果我们开发过程中需要修改其中的部分代码(这种事情经常会发生),那么我们要完成额外15倍的工作量,同时也增加了程序出错的风险。即便是我们能够一丝不苟地完成这些代码,但如何编写闪现计时器的计时事件处理程序呢?因此我们需要寻找一个更为简洁的代码编写方法。让我们先来观察一下已有的两个按钮的点击事件处理程序,如图1- 23所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 23 比较两个按钮的点击事件处理程序
经过观察,我们发现这两段程序中,共有7处不同,其中4四处与按钮本身有关,另外3处与索引值有关——按钮正面图案在随机图案列表中的位置。能否创建一个通用的过程,来处理不同按钮的点击事件,就取决于能否合理地设置过程的参数,并在调用该过程时,为参数指定确切的值。能够想到的参数就是按钮本身——按钮对象,而正面图案在随机列表中的索引值,可以通过按钮在按钮列表中的索引值获得。很不错的分析,让我们来试试看。

创建一个带参数的过程,过程名为处理点击事件,参数名为某按钮,将按钮1的代码拖拽到新建的过程中,然后对代码进行改造,如图1- 24所示:

  1. 添加一个局部变量图案索引值:求某按钮在按钮列表中的位置,前面我们讲过,按钮列表与随机图案列表中的列表项是一一对应的,因此某按钮在按钮列表中的位置也是它的正面图案在随机图案列表中的位置;
  2. 使用“任意组件”类代码来取代原来的前两行代码——设置某按钮的图像属性为正面图案,设置某按钮的启用属性为假;
  3. 当被点击的两张卡片图案不同时,添加一个局部变量翻牌1图案索引值,求出第一张翻开的卡片其正面图案在随机图案列表中的位置,并使用两个局部变量(翻牌1图案索引值及图案索引值)来求得两个卡片的正面图案;
  4. 在按钮1及按钮2的点击事件处理程序中调用该过程,并为参数指定具体按钮。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 24 创建处理点击事件过程,并调用该过程
经过测试,程序运行正常,接下来,为其余14个按钮编写点击事件处理程序,很简单——调用处理点击事件过程,并将参数设置为触发事件的按钮,结果如图1- 25所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 25 16个按钮的点击事件处理程序
在编写图1- 25的其他14个事件处理程序时,我们是将按钮1的程序复制粘贴14次,并逐一修改事件主体(按钮)及所调用过程的参数(按钮对象)。这样可以免去逐个点击按钮创建程序的重复操作。操作方法如图1- 26所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 26 复制按钮1的点击事件处理程序,并修改事件主体及参数
与一般的编程语言相比,用App Inventor开发应用会遇到一种特殊的困难,当程序中的代码过多时,屏幕就显得拥挤和混乱。因此,对代码的摆放也是一件费思量的事情。我的习惯是,将同类代码折叠之后,按顺序排列整齐,这样做一方面可以节省屏幕空间,也可以便于代码的查看和修改。如图1- 27所示,将这16段程序集中在一起,并码放整齐。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 27 将代码折叠起来并集中码放

6、代码的复用——改进闪现计时器的计时事件处理程序

与点击事件相关联的还有闪现计时器的计时事件,在图1- 23中,我们直接改写了按钮1及按钮2的图像及启用属性,现在需要将这段程序加以修改,以适用于所有的按钮。

还记得全局变量翻牌1和翻牌2中保存的是什么吗?是的,保存的正是已经被翻开的两个按钮。我们正好可以利用这两个变量,对计时程序中的前四行代码进行改写,如图1- 28所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 28 改进后的计时事件处理程序

7、测试

上述代码需要经过测试才能进入下一步开发。测试过程记录如下:

  1. 程序启动之后,16个按钮显示背面图案;✓
  2. 点击按钮1,按钮1显示正面图案;✓
  3. 点击按钮2,按钮2显示正面图案,两按钮的图案不同,但并没有闪现之后扣上;✓
  4. 在开发环境的编程视图中,弹出错误提示,如图1- 29所示。✘

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 29 测试过程中出现的错误
问题出在哪里呢?图中的错误信息中提到了“按钮”和“数字”,这让我们很容易想到对翻牌1及翻牌2的设置,它们的值要么是0,要么是某个按钮对象。

问题有可能出在全局变量翻牌1和翻牌2的设置上。我们来分析一下程序的执行顺序,如图1- 30所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 30 分析程序的执行时序
当翻开两张卡片时:

翻牌1 = 按钮1 翻牌2 = 按钮2

由于图案不相同,闪现计时器被启动,从这一时刻起开始计时,500毫秒之后,开始执行计时程序。而此时的按钮点击程序并没有停止,在屏幕标题显示“图案不同”之后,立即执行最后两条命令——设翻牌1及翻牌2的值为0。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 31 修改程序的流程
由于CPU时钟的数量级是GHz(每秒钟10亿次运算),整个按钮点击程序的执行时间也不会超过1毫秒,因此,当计时程序开始运行时,翻牌1和翻牌2的值已经被设为了0,这就是错误的原因。如图1- 30所示。

为了解决这个问题,我们调整程序的流程,如图1- 31所示。与新流程对应的代码如图1- 32所示,经过测试,程序运行正常,运行结果如图1- 33所示。

App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 32 流程调整后的代码
App Inventor编程开发集锦1-水果配对-第3课-按钮点击事件-少儿编程教育网
图1- 33 测试结果
程序中的错误,程序员称之为bug(臭虫)。要问程序员是怎样炼成的,就是在找bug的过程中炼成的。因此,不要害怕程序出错,这是人与机器交流的好机会,由此你才能更多地了解计算机,了解程序的运行机制。

我们的程序开发到这里,游戏已经具备了基本的功能,但是显然这样的游戏是毫无乐趣的,因为任何人最终都能将所有卡片翻开,而且无论如何也只能得到80分,因此我们要增加游戏的难度,并让那些记忆力超强的玩儿家能得到更高的分数。我们的方法是限制游戏时间,并用剩余时间来奖励那些高手。