JavaFX三角形绘制位置错误:未在点击处生成图形
三角形绘制位置偏移问题修复方案
问题核心
点击HBox区域的指定位置生成三角形,但实际三角形从HBox左上角开始绘制,位置与点击点不符。
代码问题分析
- 坐标未做局部转换:
event.getX()/event.getY()获取的是鼠标在HBox中的全局坐标,但自定义MyTriangle的绘制坐标系以自身左上角为原点,若未将全局坐标转换为MyTriangle的局部坐标,或未设置MyTriangle的布局位置,就会导致绘制位置偏移。 - 坐标列表清空时机错误:当前代码在绑定鼠标点击事件后立刻清空
xPoints和yPoints,虽不影响首次点击,但逻辑上存在重复点击按钮时的坐标污染风险。
修复步骤
1. 调整坐标列表清空时机
将列表清空操作移至三角形绘制完成后,同时在方法开头先清空一次列表,避免上次残留坐标干扰:
@FXML public void onButtonClicked(ActionEvent e) { ArrayList<Button> buttons = new ArrayList<Button>(); buttons.add(triangleButton); buttons.add(rectangleButton); buttons.add(circleButton); // 先清空上次残留的坐标 xPoints.clear(); yPoints.clear(); for (Button btn : buttons) btn.setDisable(true); if (e.getSource().equals(triangleButton)) { hBox.setOnMouseClicked(event -> { double x = event.getX(); double y = event.getY(); xPoints.add(x); yPoints.add(y); triangleCounter += 1; if (triangleCounter >= 3) { for (Button btn : buttons) btn.setDisable(false); triangleCounter = 0; // ... 三角形创建与绘制逻辑 hBox.setOnMouseClicked(null); // 绘制完成后清空坐标列表 xPoints.clear(); yPoints.clear(); } }); } }
2. 修正坐标转换(关键)
根据MyTriangle的实现方式,选择以下两种方案之一:
方案A:适配自定义Node(如Region/Canvas)
计算三角形的最小边界坐标,将MyTriangle的布局位置设置为该边界的左上角,再用点击坐标减去最小值作为局部绘制坐标:
// 在创建MyTriangle前计算边界 double minX = Collections.min(xPoints); double minY = Collections.min(yPoints); // 转换为相对坐标 double p1x = xPoints.get(0) - minX; double p1y = yPoints.get(0) - minY; double p2x = xPoints.get(1) - minX; double p2y = yPoints.get(1) - minY; double p3x = xPoints.get(2) - minX; double p3y = yPoints.get(2) - minY; MyTriangle triangle = new MyTriangle(p1x, p1y, p2x, p2y, p3x, p3y); triangle.drawTriangle(); // 设置布局位置到点击区域的左上角 triangle.setLayoutX(minX); triangle.setLayoutY(minY); hBox.getChildren().add(triangle);
方案B:修改MyTriangle继承Shape(如Polygon)
若MyTriangle继承自Polygon,可直接使用HBox中的全局坐标创建图形,无需额外转换:
public class MyTriangle extends Polygon { public MyTriangle(double x1, double y1, double x2, double y2, double x3, double y3) { super(x1, y1, x2, y2, x3, y3); setStroke(Color.BLACK); setFill(Color.TRANSPARENT); } public void drawTriangle() { // 继承Polygon时,构造方法已完成图形初始化,无需额外绘制 } }
这种情况下,直接将MyTriangle添加到HBox即可在点击位置显示。
3. 优化:避免重复绑定事件
可添加一个布尔标志位(如isDrawing),判断当前是否处于绘制状态,避免重复绑定鼠标点击事件导致的异常。
修复后完整Controller代码
import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.layout.HBox; import java.util.ArrayList; import java.util.Collections; public class Controller { @FXML private Button triangleButton; @FXML private Button rectangleButton; @FXML private Button circleButton; @FXML private HBox hBox; private int triangleCounter = 0, rectangleCounter = 0, circleCounter = 0; private ArrayList<Double> xPoints = new ArrayList<>(); private ArrayList<Double> yPoints = new ArrayList<>(); @FXML public void onButtonClicked(ActionEvent e) { ArrayList<Button> buttons = new ArrayList<Button>(); buttons.add(triangleButton); buttons.add(rectangleButton); buttons.add(circleButton); // 清空上次残留的坐标 xPoints.clear(); yPoints.clear(); for (Button btn : buttons) btn.setDisable(true); if (e.getSource().equals(triangleButton)) { hBox.setOnMouseClicked(event -> { double x = event.getX(); double y = event.getY(); xPoints.add(x); yPoints.add(y); triangleCounter += 1; if (triangleCounter >= 3) { for (Button btn : buttons) btn.setDisable(false); triangleCounter = 0; // 计算三角形边界并转换坐标 double minX = Collections.min(xPoints); double minY = Collections.min(yPoints); double p1x = xPoints.get(0) - minX; double p1y = yPoints.get(0) - minY; double p2x = xPoints.get(1) - minX; double p2y = yPoints.get(1) - minY; double p3x = xPoints.get(2) - minX; double p3y = yPoints.get(2) - minY; MyTriangle triangle = new MyTriangle(p1x, p1y, p2x, p2y, p3x, p3y); triangle.drawTriangle(); triangle.setLayoutX(minX); triangle.setLayoutY(minY); hBox.getChildren().add(triangle); hBox.setOnMouseClicked(null); xPoints.clear(); yPoints.clear(); } }); } } }
内容的提问来源于stack exchange,提问作者snake_case_typing
相关产品推荐
相关产品推荐

