本节书摘来华章计算机《交互式程序设计 第2版》一书中的第3章 ,第3.3节,Joshua Noble 著 毛顺兵 张婷婷 陈宇 沈鑫 任灿江 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
3.3 Processing应用程序基础
一个Processing应用程序有两个最基本的方法。一定要搞清楚它们是在何时运行的。一个是setup()方法,程序开始运行时会自动调用它。另一个是draw()方法,在程序运行期间,它会不断被执行。好了,现在就来看看方法究竟是什么。
3.3.1 setup()方法
方法是若干指令的集合。一个方法实现一个相对独立的功能。程序开始运行时,放在setup()方法中的所有指令都会被执行。你可以将它看做是一种准备工作。你平时不也经常做一些准备工作吗?比如,要开始跑步了,先要做伸展运动;要飞去国外了,得先准备好护照;要做晚餐了,先要检查一下冰箱里有没有你需要的所有食材。对于Processing应用程序而言,setup()方法的作用是做一些基本设置,参见示例3-2。
示例3-2:methods.pde
void setup(){
size(200,200);
frameRate(30);
print("all done setting up");
}
这个代码段发生了什么?嗯,第一个单词是这个方法的返回类型。void表示没有返回。第二个单词是方法的名称。返回类型和方法名称放在一起,叫做方法声明。如果你忘了什么是方法声明,请复习第2章。方法的其余部分称作方法体。符号{和}表示方法的开始和结束。中间的代码也是方法,在Processing语言中已经定义过了,可以直接拿来用。也就是说,你不必重新定义它们,只需在调用它们的时候给它们正确的参数。
size()方法
上面代码段中的第二行是size()方法。它有两个参数:程序窗口中显示区域的宽度和高度,这两个参数都以像素为单位。以像素数来表示长度是很流行的做法。图形程序、图像或视频编辑程序,以及运行这些程序的核心代码都是这样来表示长度的。抛掉英寸和厘米吧,在这个世界,所有东西都用像素数来表示。size()方法决定了程序运行窗口的大小。写出前面的代码,单击“运行”按钮。然后改变宽度和高度,再运行。你会看到size()方法的确有两个参数:
void size(width, height)
当程序员们谈到一个方法时,他们其实是指方法签名。方法签名的意思是,一个方法的名称是什么,它需要什么参数,它会返回什么值。如果你对这点不太熟悉,就再复习一下第2章,尤其是关于方法的那节。在示例3-2中,size()方法的两个参数都是整数,默认是十进制表示的。该方法返回类型是void,即没有返回。
frameRate()方法
下一个方法是frameRate()。它的参数是帧速率,决定了程序每秒要显示多少帧。Processing程序每秒显示的帧数绝不会超过你设置的值。不过它每秒显示的帧数有可能低于你的设定值,比如你的窗口里有太多东西要显示,或者你的代码效率太低。帧速率越大,意味着你的动画运动得更快,所有东西都变快了。但这也意味着,如果你的程序是数据密集型的,Processing可能会滞后。那么帧速率是怎么影响显示效果的呢?答案是:你给frameRate()设定的帧速率就是draw()方法每秒被调用的次数。
print()方法
print()方法输出一条消息到Processing集成开发环境下方的控制台。你可以输出各种类型的东西:字符串消息、数值、某类对象的值等。这就提供了一种简单途径让程序反馈一些信息;同时,当程序运行的结果和你的预期不符时,你也可以用它作为简单调试手段。比如,你希望程序产生的结果是10?那么用print()把结果显示在控制台,看看实际的结果是什么。print()输出的所有信息都显示在Processing集成开发环境下方的控制台,如图3-2所示。
图3-2:应用程序的控制台
3.3.2 draw()方法
draw()方法是应用程序绘图的地方,此外它还有其他功能。它是程序的重要特征。该方法中的任何操作都会被不断执行,每秒执行的次数就是用frameRate()方法设置的帧速率。
下面的示例3-3就是关于draw()方法的一个简单例子。
示例3-3:methods.pde
void draw() {
println("hi");
}
假设程序的帧速率是每秒30次,那么每秒钟"hi"消息字符串将会被输出到Processing集成开发环境的控制台30次。程序很简单,但它告诉我们,draw()方法的实质是定义一些按照固定频率不断执行的操作。当然,需要在setup()方法执行后生效。
通过示例3-4来对稍微复杂一些的程序进行分析。
示例3-4:expanding.pde
int x = 0;
void setup() {
size(300, 300);
}
void draw() {
// 让x变大一些
x += 2;
// 画椭圆,用x作为其长轴和短轴。圆的长轴和短轴等长,是椭圆的特例
// 圆心坐标是(150,150)
ellipse(150, 150, x, x);
// 如果x太大以至于超过窗口范围,我们看不见,则将x置0并重新开始。
if(x > 300) {
x = 0;
}
}
首先,我们定义整型变量x来存放一个值:
int x = 0;
因为x不是在方法内声明的,所以它是全局变量,在程序运行期间一直存在。也就是说,如果你在draw()方法中将x设置为20,那么在下次调用draw()方法时x的值仍然是20。全局变量很重要,你可以在某个方法中逐渐改变它的值。
注意: 这是作用域的概念。如果你对此没有什么印象,就需要复习第2章。
setup()方法是做基本设置,该程序中的setup()只是简单地设置了窗口大小。这里没有什么值得探讨的,直接跳过去看draw()方法:
void draw() {
每次调用draw(),x都会在原来的基础上加2。你也可以写成x = x +2;,但下面的写法意思一样却更简单:
x += 2;
既然x已经变大了一些,可以用它在窗口里画一个大一些的圆:
ellipse(150, 150, x, x);
注意: 关于ellipse()方法,3.4节中有更多的介绍。
如果x太大,圆就会太大,以至于无法正确地在窗口中显示出来。这时需要将x重置为0:
if(x > 300) {
x = 0;
}
}
在图3-3中可以看到,随着x不断递增,绘制的圆也越来越大。
图3-3:画圆程序演示
draw()方法很重要,因为Processing应用程序利用它来进行人机交互。比如,如果没有定义draw()方法,那么鼠标按下方法mousePressed()和鼠标移动方法mouseMove()就不会生效。这两个方法将在3.5节中讨论。你可以这样认为:draw()方法告诉应用程序,绘制每一帧时,你想监听程序发生了什么。即使draw()方法中什么也没有,你也应该定义一个draw()方法,这是一个好习惯。