【第六期(上)】窗口多开

本期知识点密度:★★★✩✩

本期要做的事:
用一个sketch生成 好多 好多 好多 好多 好多 个窗口

本期主要内容:

  • 一:玩转Processing窗口属性
  • 二:Processing的本质
  • 三:如何生成好多窗口

太长不看版:

1
2
3
4
5
● 一个普通的类不能生成窗口
● 一个类继承了PApplet,它就可以生成一个窗口
● 想要好多窗口,就写好多继承PApplet的类
● 通过surface.setLocation();改变窗口位置即可
● 前往文章末尾拷贝代码

下面开始逐个讲解:

玩转Processing窗口属性

第一期 中,我们讲过7种绘制模式,本期需要用的绘制模式,是JAVA2D;
在这种绘制模式中,窗口载体使用的是 java.awt.Frame(在2.x中可以直接访问该frame对象),也就意味着,我们可以根据Frame的特性来自定义窗口的各项参数。

在Processing 3.x中,官方为了跨平台兼容,将frame进一步封装为一个PSurface对象:surface.
所以我们需要调用surface,对Processing的窗口,进行魔改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PImage icon;

void setup() {
icon = loadImage("bai-32.png");//载入图标文件
size(300, 200);
background(0);

surface.setSize(500, 500); //重设窗口大小
surface.setLocation(0, 0); //设置窗口位置
surface.setTitle("Ohhhh!!!!");//设置窗口标题
surface.setIcon(icon); //设置窗口图标
surface.setAlwaysOnTop(true); //设置是否窗口保持置顶
surface.setResizable(true); //设置窗口可变
surface.setCursor(HAND); //设置鼠标样式 ARROW, CROSS, HAND, MOVE, TEXT, WAIT
}

留意窗口的变化:

  • 窗口并非是size中定义的300×200,而是被重设为了500×500
  • 窗口自身的位置被调整到左上角(0, 0)点
  • 窗口的标题变成了“Ohhhh!!!!”
  • 窗口图标变成了我们自定义的图标
  • 窗口始终置顶
  • 窗口大小可随意拖拽
  • 鼠标样式变成了小手 这个例子中,我们只选择了一些常用的函数进行演示,更多相关功能请参考 Processing源码

Processing的本质

————以下是硬核技术时间————
在Processing中,我们会经常使用到class,也就是“类”
但Processing的“类”与其他编程语言中常见的“类”并不相同
它们的本质是Java的 内部类
这个特性也造就了Processing的设计理念:Wrapper Facade
意味着用户无需考虑复杂的内部实现原理,直接通过清晰简单的接口来实现功能。(这种设计哲学也是我喜欢Processing的原因之一)

再聊聊Processing的代码封装
用户在PDE中写的所有代码,都会被二次加工成Java代码,再丢进Java虚拟机中运行。
比如用户只写了一段简单的代码:但最终运行的代码被加工成了这样:
可以发现:

  • 最前面import了很多东西
  • 用户写的所有的代码被放在了一个更大的class里面,class名与PDE工程名相同,并继承了PApplet
  • size()函数被移动到了一个新的函数void settings()里面
  • void setup()中的内容除了size之外直接照搬
  • void draw()里的内容直接照搬
  • 后面加上了主函数,也就是程序入口

——————硬核时间结束——————
这些都是Processing为了降低编程复杂度而做的功课,目的就是为了把初学者和繁琐的步骤隔离开,把写代码变成一种乐趣。
但是现在,我们要离开这个精致的温室,去探究它的本源了


生成好多窗口

我们在上面提到过,加工后的代码被放进了一个大类里面,而且继承了PApplet
原因是每一个继承了PApplet的类都可以成为一个完整的Processing程序
它有自己的窗口,有自己的void setup()和void draw()…

如果我们想要生成新的窗口,就需要再写一个继承PApplet的类,就像这样:

1
2
3
4
5
6
7
8
9
10
11
void setup() {
Inner in1 = new Inner();
Inner in2 = new Inner();
Inner in3 = new Inner();
}
class Inner extends PApplet { //继承了PApplet
Inner() { //构造函数
super(); //先执行父类的构造函数
PApplet.runSketch(new String[]{"Inner"}, this);//然后运行自己
}
}

这段代码可以直接生成四个窗口(一个原窗口+三个新窗口)
又由于我们离开了精致的温室,不能再在void setup()里写size了,所以如果要设置窗体大小,void settings()函数也需要老老实实加上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Inner[] inners = new Inner[50]; //创建一个数组存储这些窗口

void settings() {
size(300, 200);
}
void setup() {
background(255);
for (int i=0; i<inners.length; i++) {
inners[i] = new Inner(); //初始化每个窗口
}
}
class Inner extends PApplet {
Inner() {
super();
PApplet.runSketch(new String[]{"Inner"}, this);
}
void settings() {
size(200, 200);
}
void setup() {
surface.setLocation((int)random(1920), (int)random(1080));//随机设置每个窗口的位置,并设置背景色
background(0);
}
}

  • 【第六期(上)】,已经讲解完毕,我们已经实现了创建多个窗口,并且知道了如何改变每个窗口的位置。
  • 【第六期(中)】,我们会暂时搁置本期内容,用最基础的(画圆圈的)方式,讲一讲吸引和排斥的实现原理
  • 【第六期(下)】,我们会将前两期的内容结合起来,实现窗口之间互相吸引与排斥的效果