NetBeans项目

第二个迷宫绘图版本

在第二个版本的迷宫绘图程序中,我们将添加在迷宫中放置物体的能力,除了墙壁。

我们将在这个版本的代码中演示的主要新特性是处理键盘事件的能力。用户将能够通过按键盘上的特定键在赢博体育程序中做许多事情。

  1. 用户可以按退格键删除最后放置的墙。
  2. 用户可以通过键盘上的“p”键从画墙模式切换到物体放置模式。
  3. 用户可以通过按“r”键表示红色,按“g”键表示绿色,按“b”键表示蓝色来改变他们放置的物体的颜色。

在地图上添加宝藏

我们将在迷宫中放置的物品是代表宝藏的简单矩形。为了实现这些新对象,我们建立了一个Treasure类:

公共类宝藏{私有矩形;private Color颜色;private double snap(double x) {double n = Math。楼层(x / 40);返回n * 40.0;}公共宝藏(两个x,两个y,颜色c){这个。颜色= c;rect = new Rectangle();rect.setX (x - 15.0);rect.setY (y - 15.0);rect.setWidth (30.0);rect.setHeight (30.0);rect.setFill(颜色);}公共形状getShape(){返回矩形;}公共无效setLocation(双x,双y) {rect.setX(x-15.0);rect.setY (y - 15.0);}公共无效snapToGrid(双x,双y) {rect.setX(snap(x)+ 5.0);rect.setY(提前(y) + 5.0);}公共无效写入(printwwriter输出){字符串颜色str = “红色”;if(color == color . blue) colorStr = “蓝色”;if(color == color . green) colorStr = "green";out.println(Math.round(rect.getX()) + " " + Math.round(rect.getY()) + " " + colorStr);}}

Treasure对象本质上是一个彩色矩形的容器。与Wall类一样,Treasure类包含支持在屏幕上拖动Treasure对象的方法,以及将其自身写入文本文件的方法。

现在,MazePane需要同时支持绘制墙段和宝藏对象,我们需要向MazePane类添加一些额外的成员变量:

private ArrayList<Wall> walls;private ArrayList<宝>宝;私墙拖拽;私人宝藏配售;private Color颜色;私有布尔drawingWalls;

拖动成员变量允许我们在绘制墙壁时访问正在拖动的当前Wall,而放置成员变量允许我们在地图上放置宝藏时访问正在拖动的当前Treasure对象。颜色变量将允许我们记住在放置新的宝藏对象时应该使用什么颜色。drawingWalls成员变量在绘制墙壁模式下为true,在放置宝藏模式下为false。

增加对关键事件的支持

由于这个赢博体育程序还需要响应键盘上的按键,我们需要在MazePane类的构造函数中添加一个额外的setOn方法调用:

这一点。setOnKeyPressed(e -> keyPress(e));

当用户按下键盘上的一个键时,将调用MazePane中的keyPress()方法。

public void keyPress(KeyEvent e) {switch (e.getCode()) {case R: color = color . red;打破;case G: color = color . green;打破;case B: color = color . blue;打破;case BACK_SPACE: Wall toRemove = walls.get(walls.size() - 1);walls.remove (toRemove);this.getChildren () .remove (toRemove.getShape ());打破;情形P: drawingWalls = !drawingWalls;打破;}}

响应按键事件的方法采用javafx.scene.input.KeyEvent类型的单个参数。这个KeyEvent对象携带着关于按键事件的信息。KeyEvent对象的getCode()方法返回一个数字代码,该代码标识用户按下的键盘上的键。我们通常使用switch语句为我们期望用户按下的不同键设置不同的case。switch语句中使用的常量在KeyCode枚举中定义。您可以在这里找到可用关键代码的完整列表。

要使关键事件在赢博体育程序中正确工作,我们还需要做最后一件事。我上面展示的代码足以让MazePane响应关键事件,但是我们还需要首先告诉系统,MazePane对接收关键事件感兴趣。在JavaFX中,我们通过调用窗格类中的requestFocus()方法来实现这一点。JavaFX为我们提供的一个不幸的要求是,requestFocus()调用只有在将MazePane放置在场景中时才能正常工作。这意味着我们不能在MazePane的构造函数中调用requestFocus(),因为该构造函数将在MazePane放置在场景中之前被调用。我们也不能在赢博体育程序控制器的initialize()方法中调用这个方法,因为它也会在场景中安装MazePane之前被调用。绕过这些限制的唯一方法是在控制器类中放置一个特殊的方法,然后在适当的时候调用该方法。我们放在控制器类中的方法是

public void focusMaze() {maze.requestFocus();}

调用它的代码进入App类的start()方法:

@Override public void start(Stage Stage)抛出IOException {FXMLLoader loader = new FXMLLoader(App.class.getResource("primary.fxml"));Scene Scene = new Scene(loader.load(), 640,480);PrimaryController controller = (PrimaryController) loader.getController();controller.focusMaze ();stage.setScene(现场);scene.getRoot()。setStyle(“-fx-font-family:无衬线”);阶段。setTitle(“迷宫图”);stage.show ();}