您应该发布您的 Rectangle 类,以便其他人更容易测试和提供帮助。
正如 Basil 指出的 (+1),当有点击事件时,您只会为一帧渲染一个新的矩形。
我的想法是,每次单击按钮时,都会创建一个新的矩形对象,除了旧的对象。因此,如果我点击按钮 5 次,我应该有 5 个矩形。
这个说法有点模棱两可。我知道您希望每次单击都呈现一个矩形,但是在单击处理程序中,矩形具有完全相同的尺寸和坐标。即使您会进行一些小修复,在彼此顶部渲染 5 个相同的矩形也可能看起来就像是一个矩形。
关于您发布的代码,这对我来说很突出:
-
Rectangle rect; // rect begins as null:如果你在下面有这个矩形的目的是什么:ArrayList<Rectangle> rectList;?
-
showRect(); 在draw() 中被调用:它在rectList 上循环,不仅调用displayRect(),我认为它会呈现当前的矩形,而且还会在下一行重新呈现相同的数据(rect(r.getXvalue(), r.getYvalue(), r.getWvalue(), r.getHvalue()); )
- 在下面,在同一个列表上的 for 循环再次调用
displayRect()。我的猜测是 2 out 3 调用渲染矩形是多余的。 (因此,数组列表也被键入,不需要像这样转换:(Rectangle)rectList.get(i)),rectList.get(i) 就足够了)
我唯一的其他小警告是关于命名:理想情况下,您希望在处理中坚持使用 Java naming conventions。 (例如getXValue()而不是getXvalue()等)
关于 ControlP5 按钮,您可以使用controlEvent(),这比设置回调要简单一些。更简单的是使用这种自动变量插入功能。简而言之,如果一个函数的名称与按钮的名称相同,它将被自动调用:
自动控制器事件检测
ControlP5 提供了一系列控制器,可让您在草图运行时轻松更改和调整值。每个控制器都由创建控制器时分配的唯一名称标识。 ControlP5 在您的草图中定位变量和函数,并将控制器自动链接到匹配的变量或函数
(来自controlP5 reference)
这是一个基本示例,每次单击按钮时都会向控制台打印一条消息:
import controlP5.*;
ControlP5 cp5;
void setup() {
size(1000, 1000);
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw(){
background(255);
}
void rectangle(){
println("rectangle button clicked");
}
(我保留名称 rectangle 而不是 Rectangle 以符合 Java 命名约定。文本标签无论如何都以大写显示)
回到你的主要问题,如果你想在每次按下按钮时添加新的矩形并渲染它们,代码就像这样简单:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
int x = 100;
int y = 100;
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
}
void rectangle(){
rectList.add(new Rectangle(x, y, 100, 100));
// increment x, y to avoid superimposed rectangles
x += 50;
y += 50;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
// currently not used
public int getX(){
return x;
}
public int getY(){
return x;
}
public int getWidth(){
return x;
}
public int getHeight(){
return x;
}
}
Rectangle rect; 脱颖而出。如果这是一个 OOP 家庭作业或练习,也许目的是拥有一个基本的绘图应用程序功能,用户可以拥有一个矩形绘图工具?
如果是这种情况,rect 可能是选择矩形,它可以克隆到 rectList 中,所以它仍然存在。
你可以像这样实现矩形选择:
- 按下鼠标时记住坐标:这些是选择的起点
- 当鼠标被拖动时,终点坐标是当前鼠标坐标,因此选择矩形的尺寸是当前鼠标坐标和之前存储的鼠标坐标之间的差异
- 释放鼠标后,重置选择矩形(使其不再显示)
这是一个基本的示例草图:
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup(){
size(1000, 1000);
}
void draw(){
background(255);
selection.display();
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
selection.w = selection.h = selection.x = selection.y = 0;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
}
将Rectangle 属性重置为 0 可以很好地封装到一个方法中:
void reset(){
x = y = w = h = 0;
}
释放处理程序还可用于向rectList 添加一个新矩形,该矩形具有与选择相同的属性 (x, y, w, h),但在重置选择之前。类似:
void mouseReleased(){
// add a copy of the selection to rectList
rectList.add(new Rectangle(selection.x, selection.y, selection.w, selection.h));
// reset selection
selection.reset();
}
同样,复制功能也可以很好地封装为方法:
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
将它们放在一起看起来像这样:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
// draw previous rectangles (black)
stroke(0);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
// draw current selection (green)
stroke(0, 192, 0);
selection.display();
}
void rectangle(){
println("selected drawing tool is rectangle");
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
// add a new rectangle to the list: a copy of the selection
rectList.add(selection.copy());
// reset selection
selection.reset();
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
void reset(){
x = y = w = h = 0;
}
}
在这个阶段,按钮有点多余,但是如果需要其他形状,它可能在将来很有用(例如,Ellipse 显然很容易实现,因为ellipse() 具有与@987654355 相同的参数@,只需要确保 ellipseMode(CORNER) 设置为使用与矩形相同的选择 x,y 坐标)
希望这是有用的。如前所述,最初的代码看起来有点乱,好像是在截止日期之前匆忙拼凑起来的。
(我假设这是因为它让我想起了我作为学生的代码:))
我建议您离开电脑走一小段路,记住任务是什么,然后在纸上将任务分解成小而清晰、易于实施的子任务。一旦清楚了,就可以一次单独地执行一个子任务。最初代码可能会中断或变得混乱,但最终它会起作用(与整个绘图程序相比,它会更容易编写)。一旦成功,清理代码以便删除所有不必要的代码,并且很容易将代码移动到另一个草图并运行它而不会出错。对每个子任务重复该过程,这将导致多个最小草图解决一个问题。一旦单独解决了所有部分,您就可以开始将代码放在一个主草图中,但是我建议一次添加一个子任务代码并首先进行测试。当混合来自多个草图的代码时,可能会出现冲突/错误,与一次合并所有子任务草图相比,一次合并两个草图要容易得多。祝你好运!