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

如何使用JavaFX与SceneBuilder将Puffer类的Group绘制到Canvas上

JavaFX + SceneBuilder 绘图问题求助

我是SceneBuilder与JavaFX的新手,现在遇到了绘图问题。我有Puffer、TestMain和MainViewController三个类,之前单独在Canvas绘图、用Puffer类运行都正常,但现在想结合SceneBuilder实现:点击按钮把Puffer类里的Group内容绘制到Canvas上,修改Puffer类后没效果,不知道怎么解决。


Puffer类代码

public class Puffer {
    
    Group root = new Group();
    
public void draw() {
    for (int x = 0; x < 800; x++) {
        for (int y = 0; y < 600; y++) {
            Complex z0 = new Complex(0.11, 0.123); //!!!!!!!!!!!!! under 1
            Complex c = new Complex(x / 400.0 - 2, 1 - y / 400.0);

            if (isBounded(iterate(z0, c))) {
                drawPoint(x, y, root);
            }
        }
    }

//    primaryStage.setScene(new Scene(root, 800, 600));
//    primaryStage.show();
}


public void drawPoint(int x, int y, Group root) {
    int max = 255;
    int min = 0;
    int range = max - min + 1;


    Line line = new Line(x, y, x, y);
   // line.setStroke(Color.rgb((int)(Math.random() * range) + min,(int)(Math.random() * range) + min,(int)(Math.random() * range) + min));
    root.getChildren().add(line);
}

public Complex iterate(Complex z0, Complex c) {
    Complex zn = z0;

    for (int i = 0; i < 20; i++) {
        zn.square().add(c);
    }

    return zn;
}

public boolean isBounded(Complex zn) {
    return zn.module() < 2;
}

MainViewController类代码

public class MainViewController {
    @FXML
    Canvas canvas;

    // Event Listener on Button.onAction
    @FXML
    public void btnOkClicked(ActionEvent event) {
        System.out.println("Test");
    }
    
     @FXML
        public void drawCanvas(){

         
//          GraphicsContext gc = canvas.getGraphicsContext2D();
//          gc.setLineWidth(3);
//          gc.setStroke(Color.BLACK);
//          System.out.println("drawCanvas");
//
//          try {
//              canvas.setOnMousePressed(event -> {
//                  System.out.println("Mouse click");
//                  gc.beginPath();
//                  gc.lineTo(event.getSceneX(), event.getSceneY());
//                  gc.stroke();
//              });
//
//              canvas.setOnMouseDragged(event -> {
//                  System.out.println("Mouse dragged");
//                  gc.lineTo(event.getSceneX(), event.getSceneY());
//                  gc.stroke();
//              });
//          }catch (Exception e){
//              System.out.println(e);
//              System.exit(0);
//          }

        }

TestMain类代码

public class TestMain extends Application {

    @Override
    public void start(Stage s1) throws Exception {
    try {
        Parent root = FXMLLoader.load(getClass().getResource("MainView.fxml"));
        Scene scene = new Scene(root);
        
        s1.setTitle("Test");
        s1.setScene(scene);
        s1.show();
        
    }catch(Exception ex) {
        ex.printStackTrace();
    }
        
        
    }
    
    public static void main(String[] args) {
        launch(args);
    }
       

解决方案

核心问题是Group和Canvas是JavaFX两种不同的绘图容器,不能直接将Group的子元素放到Canvas上,必须把Puffer的绘图逻辑改成适配Canvas的GraphicsContext API,同时修复迭代方法的逻辑错误:

  1. 重构Puffer类,适配Canvas绘图
public class Puffer {
    // 移除原Group成员,改为接收GraphicsContext和画布尺寸
    public void draw(GraphicsContext gc, int canvasWidth, int canvasHeight) {
        gc.setStroke(Color.BLACK); // 设置画笔颜色
        for (int x = 0; x < canvasWidth; x++) {
            for (int y = 0; y < canvasHeight; y++) {
                Complex z0 = new Complex(0.11, 0.123);
                Complex c = new Complex(x / 400.0 - 2, 1 - y / 400.0);

                if (isBounded(iterate(z0, c))) {
                    drawPoint(gc, x, y);
                }
            }
        }
    }

    // 修改为用GraphicsContext画点
    public void drawPoint(GraphicsContext gc, int x, int y) {
        // 画1像素的点
        gc.strokeLine(x, y, x, y);
        // 如需彩色可取消下面注释
        // int r = (int)(Math.random()*256);
        // int g = (int)(Math.random()*256);
        // int b = (int)(Math.random()*256);
        // gc.setStroke(Color.rgb(r,g,b));
        // gc.strokeLine(x, y, x, y);
    }

    // 修复迭代逻辑:必须将计算结果赋值给zn,否则迭代无效
    public Complex iterate(Complex z0, Complex c) {
        Complex zn = z0;
        for (int i = 0; i < 20; i++) {
            zn = zn.square().add(c);
        }
        return zn;
    }

    public boolean isBounded(Complex zn) {
        return zn.module() < 2;
    }
}
  1. 修改MainViewController,绑定按钮触发绘图
public class MainViewController {
    @FXML
    Canvas canvas;

    @FXML
    public void btnOkClicked(ActionEvent event) {
        drawOnCanvas();
    }

    @FXML
    public void drawCanvas(){
        drawOnCanvas();
    }

    // 提取公共绘图逻辑
    private void drawOnCanvas() {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        // 清空画布原有内容
        gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        // 实例化Puffer并绘图
        Puffer puffer = new Puffer();
        puffer.draw(gc, (int)canvas.getWidth(), (int)canvas.getHeight());
    }
}
  1. 确认FXML绑定正确
    在SceneBuilder中选中按钮,在On Action下拉菜单中选择对应的方法(btnOkClicked或drawCanvas),同时确保FXML的fx:controller属性指向MainViewController的全类名。

关键说明

  • Group是节点容器,Canvas是像素级绘图组件,两者API不兼容,必须用GraphicsContext操作Canvas。
  • 原iterate方法未保存迭代结果,导致所有计算失效,这是核心bug之一。
  • 绘图前调用clearRect可避免重复绘制内容重叠。

内容的提问来源于stack exchange,提问作者wonkas42

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:18:20