You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX三角形绘制位置错误:未在点击处生成图形

三角形绘制位置偏移问题修复方案

问题核心

点击HBox区域的指定位置生成三角形,但实际三角形从HBox左上角开始绘制,位置与点击点不符。

代码问题分析

  1. 坐标未做局部转换:event.getX()/event.getY()获取的是鼠标在HBox中的全局坐标,但自定义MyTriangle的绘制坐标系以自身左上角为原点,若未将全局坐标转换为MyTriangle的局部坐标,或未设置MyTriangle的布局位置,就会导致绘制位置偏移。
  2. 坐标列表清空时机错误:当前代码在绑定鼠标点击事件后立刻清空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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:06:08