Oh!Coder

Coding Life

有趣的Processing-鼠标

| Comments

Hi!大家好。经过前几次的共同学习,我们了解在Processing中如何画出基本的图形,填充各种颜色,以及面向对象编程的基本概念。其实,综合前几次的学习,我们已经能够显示一些有趣的图形。但是呢,如果我们现在想通过鼠标与之进行交互,那又要怎样去做呢?嗯,这一次,我们将共同学习如何通过鼠标与图形进行互动!

鼠标的坐标

在前几次的学习中,我们了解到,Processing的2D坐标系统,是以窗口的左上角为起点,作为(0, 0)点,x轴正方向向右延伸,y轴正方向向下延伸。而描述鼠标的位置信息,用的就是坐标值。坐标值其实就是一个点,包括了x坐标值和y坐标值。所遵循的坐标系,就是Processing的2D坐标系统。

那如何实时获取鼠标的坐标值呢?Processing直接给出了两个变量,这两个变量是系统定义好的,直接拿来就可以使用,分别是mouseXmouseY。比如你想实时查看当前坐标的位置,可以直接在draw()方法里打印出这两个值。

1
2
3
void draw() {
  println(mouseX + " : " + mouseY);
}

在程序框架的draw()方法里,使用系统提供的println()方法,即可实时打印出鼠标的x坐标和y坐标值。

那既然我们知道了鼠标的实时坐标值,如果想让一个圆形跟随鼠标一起动起来,就很容易实现。

为了更好的理论结合实际,让我们先创建一个新的项目窗口。

processing-new-window

图片来源:Processing新项目窗口

将下面代码添加到新项目窗口中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 初始化窗口大小
  size(100, 100);
  // 清除填充色
  noStroke();
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色。
  // 由于是在draw()方法中设置背景色,
  // 所以背景色会被不停的刷新。
  background(126);
  // 画圆形。
  // 中心点为鼠标的x坐标和y坐标值。
  ellipse(mouseX, mouseY, 33, 33);
}

点击下图中三角形按钮,编译并运行代码。

processing-window-menu

图片来源:Processing新项目窗口中的菜单栏

运行的结果,如下图所示。

processing-fun-mouse-1

图片来源:Processing程序执行结果

有时候,我们可能想知道,每次鼠标的移动间距,所以这时候就需要记录上一次的鼠标坐标点。出于这一点考虑,Processing为我们提供了这样一组变量,用来记录上一次鼠标的坐标点,变量的名称为pmouseXpmouseY,和mouseXmouseY很像,只是变量名称的前面多了一个字母p。这样的话,如果我们想记录鼠标两次移动之间的距离,只要用mouseX - pmouseXmouseY - pmouseY即可,非常方便吧!So easy~

鼠标按键

鼠标除了有坐标点以外,还有鼠标按键。那对于鼠标按键状态的获取,Processing也为我们提供了现成的变量。对于任意鼠标按键按下的状态,我们可以统一使用mousePressed来判断。举例来说明。

首先,还是新建一个项目窗口。

将其添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 初始化窗口大小
  size(100, 100);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  // 由于是在draw()方法中设置背景色,
  // 所以背景色会被不停的刷新。
  background(204);
  // 判断鼠标是否有按键按下。
  // true为有按键按下,
  // 否则无按键按下。
  if (mousePressed == true) {
    // 填充白色
    fill(255);
  } else {
    // 填充黑色
    fill(0);
  }
  // 画矩形
  rect(25, 25, 50, 50);
}

运行上述代码,效果图看起来像是下面这个样子。

processing-fun-mouse-2

图片来源:Processing程序执行结果

这里演示的例子,只是笼统的判断了鼠标按键是否有按下。如果想判断是哪个按键按下,则就要用另外一个变量了。与之类似,Processing提供的变量名为mouseButton。普通鼠标通常有三个按键,所以判断的状态也就包括了三种,分别为LEFTCENTER以及RIGHT。在上述例子之上,我们做一点小小的修改。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 初始化窗口大小
  size(100, 100);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 判断鼠标左键是否按下
  if (mouseButton == LEFT) {
    // 填充黑色
    fill(0);
  } else if (mouseButton == RIGHT) {
    // 判断鼠标右键是否按下,
    // 并填充白色
    fill(255); // White
  } else {
    // 若没有按键按下,则填充灰色
    fill(126); // Gray
  }
  // 画矩形
  rect(25, 25, 50, 50);
}

鼠标事件

上面获取鼠标的状态,我们可以统称为鼠标数据。那除了获取鼠标数据以外,我们还可以感知鼠标事件。如果细心,你会发现,上述过程中,我们获取鼠标数据都是在编程框架的draw()方法中。这个draw()方法会不停地被系统循环调用,所以我们获取鼠标的数据也都是实时的。但如果我们只想在鼠标状态发生变化的时候获取鼠标的数据,这个时候如果我们还放在draw()里进行调用,获取就不太合适了。Processing为我们考虑到了这一点,所以提供了几个常用的鼠标事件。这些事件作为单独的方法被系统调用,而且只在鼠标状态发生变化的时候,调用一次,所以这些事件不会没由头的不停调用。对于鼠标来说,Processing为我们提供四个常用的事件。分别如下:

  • mousePressed()
  • mouseReleased()
  • mouseMoved()
  • mouseDragged()

具体来说,对于mousePressed()方法,只有在鼠标按键按下的那一瞬间,会被系统调用一次。同样,mouseReleased()方法,只有在鼠标按键弹起的那一瞬间,会被系统调用一次。mouseMoved()方法会在鼠标移动的时候,不停的被系统调用。mouseDragged()方法,会在鼠标按键按下,并进行拖拽的时候,不停的被系统调用。好,我们还是举一个简单的例子。

首先呢,还是新建一个项目窗口。

添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 定义四个整型变量。
// 前两个为鼠标拖拽坐标值。
// 后两个为鼠标移动坐标值。
int dragX, dragY, moveX, moveY;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(100, 100);
  // 清空填充色
  noStroke();
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(204);
  // 设置填充色为黑色
  fill(0);
  // 画黑色圆形。
  // 此圆形会随着鼠标拖拽进行移动。
  ellipse(dragX, dragY, 33, 33);
  // 设置填充色为灰色
  fill(153);
  // 此圆形会随着鼠标移动进行移动。
  ellipse(moveX, moveY, 33, 33);
}
// 鼠标移动方法。
// 当鼠标移动的时候,
// 系统会触发鼠标移动事件,并调用此方法。
void mouseMoved() {
  // 鼠标移动时,获取鼠标坐标,
  // 并改变灰色圆形位置。
  moveX = mouseX;
  moveY = mouseY;
}
// 鼠标拖拽方法。
// 当鼠标拖拽的时候,
// 系统会触发鼠标拖拽事件,并调用此方法。
void mouseDragged() {
  // 鼠标拖拽时,获取鼠标坐标,
  // 并改变黑色圆形位置。
  dragX = mouseX;
  dragY = mouseY;
}

运行上述代码,体验一下效果。程序执行结果大致如下。

processing-fun-mouse-3

图片来源:Processing程序执行结果

这个例子里,用到了其中两个鼠标事件,一个是鼠标的拖拽,另一个是鼠标的移动,对于鼠标的按下和抬起,其实大同小异。这里要注意的是,按下和抬起都是在鼠标状态改变的时候,只触发一次。所以,根据应用场景的不同,如果想获取鼠标的连续状态,可以在draw()方法里通过调用mouseButton来获取鼠标状态,如果只是想触发一次,那么可以选择在mousePressed()mouseReleased()方法里获取鼠标的坐标。

鼠标的icon

前面我们讲了如何获取鼠标的数据,也了解了鼠标的四个事件。那么关于鼠标,还有最后一个话题,那就是如何更改鼠标的icon。

Processing里提供了自定义鼠标的功能。如果想使用系统默认提供的鼠标icon,Processing定义了六个常量,来标示系统常用鼠标的icon,分别是ARROWCROSSHANDMOVETEXT以及WAIT。这六个系统提供的鼠标icon,会随着操作系统的不同更改变。具体如何使用呢?我们还是举一个简单的例子。

首先,还是新建一个项目窗口,添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(100, 100);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(204);
  // 判断鼠标是否按下
  if (mousePressed == true) {
    // 将鼠标的icon改为HAND
    cursor(HAND);
  } else {
    // 将鼠标的icon改为CROSS
    cursor(CROSS);
  }
  // 以鼠标的x坐标画一条线
  line(mouseX, 0, mouseX, height);
  // 以鼠标的y坐标画一条线
  line(0, mouseY, height, mouseY);
}

运行上述代码,显示运行结果,大致的效果如下:

processing-fun-mouse-4

图片来源:Processing程序执行结果

由于截图的时候,无法将鼠标icon截取下来,所以上图只显示了两条线,如果代码运行正确,你可以在程序运行的窗口中点击鼠标,看到鼠标icon的更改。

当然,除了更改成系统提供的以外,还可以自定义鼠标的图形。Processing提供了noCursor()方法,来隐藏鼠标默认的icon,然后可以自定义一个图形,将鼠标的坐标值赋值给图形,那么这个图形就可以看成为鼠标的icon。自定义的图形可以是通过Processing画出的,也可以从外部加载图片文件,都可以。

总结

回顾一下,通过这次学习,我们大概学了三部分内容。第一部分是获取鼠标的数据,其中包括鼠标的点击状态,鼠标的坐标值,以及鼠标的具体按键状态。这部分,涉及到的鼠标状态的有mousePressedmouseButton。获取鼠标当前坐标值的有mouseXmouseY,获取鼠标上一次临近坐标值的有pmouseXpmouseY。第二部分是鼠标的事件,Processing主要为我们提供了四个事件,分别是:

  • mousePressed()
  • mouseReleased()
  • mouseMoved()
  • mouseDragged()

这个四个事件都是在鼠标发生变化的时候,系统自动进行调用。第三部分,就是自定义鼠标的icon,自定义icon既可以使用系统提供的默认icon,也可以自己画图或使用外部图片资源,都可以。

嗯,关于鼠标,这次我们就学了差不多这么多。

下期预告

既然鼠标已经学了,很自然的,还有键盘嘛!嗯,下一次,我们就学习Processing中的键盘!

Comments