如何使用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,同时修复迭代方法的逻辑错误:
- 重构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; } }
- 修改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()); } }
- 确认FXML绑定正确
在SceneBuilder中选中按钮,在On Action下拉菜单中选择对应的方法(btnOkClicked或drawCanvas),同时确保FXML的fx:controller属性指向MainViewController的全类名。
关键说明
- Group是节点容器,Canvas是像素级绘图组件,两者API不兼容,必须用
GraphicsContext操作Canvas。 - 原
iterate方法未保存迭代结果,导致所有计算失效,这是核心bug之一。 - 绘图前调用
clearRect可避免重复绘制内容重叠。
内容的提问来源于stack exchange,提问作者wonkas42
相关产品推荐
相关产品推荐

