JavaFX应用中自定义Canvas图形无法显示的问题求助
问题:JavaFX自定义Canvas无法显示函数图形
我大学教授布置了作业,要求实现一个显示函数图形的简单GUI。教授提供了3个基础文件:FunctionCanvas、FunctionCurve和Main,我自行编写了FXML文件和Controller,但运行后带有函数图形的Canvas始终无法显示,试过网上多种方案都没解决,使用IntelliJ IDEA开发。
教授提供的代码
FunctionCanvas.java
package Aufgabe1.jfx; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; final class FunctionCanvas extends Canvas { private double c1 = 1, d1 = 0, c2 = 1, d2 = 0; void setFunctionParameters(double c1, double d1, double c2, double d2) { this.c1 = c1; this.d1 = d1; this.c2 = c2; this.d2 = d2; } FunctionCanvas() {} private static final float v = 244f / 255; private static final Color backGroundColor = Color.color(0, 0, 0); private static final int yOffset = 20; void drawFunctionCurve() { GraphicsContext gc = getGraphicsContext2D(); //float v = 244f / 255; gc.setFill(backGroundColor); gc.fillRect(0, 0, getWidth(), getHeight()); double h = this.getHeight() - 2 * yOffset; int xOffset = 40; double w = this.getWidth() - 2 * xOffset; double yZero = yOffset + h / 2; gc.setFill(Color.BLACK); gc.fillText("f(x)", xOffset - 30, yOffset); gc.fillText("0", xOffset - 25, yZero + 5); gc.fillText("2π", xOffset + w - 5, yZero - 5); gc.setLineWidth(1.0); gc.setStroke(Color.GRAY); gc.strokeLine(xOffset, yOffset, xOffset, yOffset + h); gc.strokeLine(xOffset, yZero, xOffset + w, yZero); gc.setLineWidth(1.5); gc.setStroke(Color.INDIANRED); for (int x = 0; x < w; x++) { int y = (int) ((h / 2) * sinCosFunc(x * 2 * Math.PI / w)); gc.strokeLine(xOffset + x, yZero - y, xOffset + x, yZero - y); } } private double sinCosFunc(double x) { return Math.sin(c1 * x + d1) * Math.cos(c2 * x + d2); } }
FunctionCurve.java
package Aufgabe1.jfx; import javafx.application.Application; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class FunctionCurve extends Application { public FunctionCurve() { } @Override public void start(Stage stage) throws Exception { int width = 670; int height = 520; //Written by me FXMLLoader loader = new FXMLLoader(getClass().getResource("1gui.fxml")); Parent root = loader.load(); Scene scene = new Scene(root, width, height); stage.setTitle(this.getClass().getSimpleName()); stage.setScene(scene); stage.centerOnScreen(); stage.show(); } }
Main.java
package Aufgabe1.jfx; final class Main { private Main() {} public static void main(String[] args) { javafx.application.Application.launch(FunctionCurve.class, args); } }
自行编写的代码
1gui.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <SplitPane dividerPositions="0.08892617449664429" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" orientation="VERTICAL" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Aufgabe1.jfx.Controller"> <items> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0"> <children> <HBox prefHeight="48.0" prefWidth="597.0"> <children> <Label prefHeight="25.0" prefWidth="25.0" text="c1"> <padding> <Insets left="5.0" right="5.0" /> </padding> </Label> <Spinner editable="true" prefHeight="10.0" prefWidth="50.0" /> <Label prefHeight="25.0" prefWidth="25.0" text="d1"> <padding> <Insets left="5.0" right="5.0" /> </padding> </Label> <Spinner editable="true" prefHeight="10.0" prefWidth="50.0" /> <Label prefHeight="25.0" prefWidth="25.0" text="c2"> <padding> <Insets left="5.0" right="5.0" /> </padding> </Label> <Spinner editable="true" prefHeight="10.0" prefWidth="50.0" /> <Label prefHeight="25.0" prefWidth="25.0" text="d2"> <padding> <Insets left="5.0" right="5.0" /> </padding> </Label> <Spinner editable="true" prefHeight="10.0" prefWidth="50.0" /> <Button mnemonicParsing="false" text="Button"> <HBox.margin> <Insets left="5.0" right="5.0" /> </HBox.margin> </Button> <Button mnemonicParsing="false" text="reset"> <HBox.margin> <Insets left="5.0" right="5.0" /> </HBox.margin> </Button> </children> </HBox> </children></AnchorPane> <AnchorPane fx:id="_canvas" prefHeight="600.0" prefWidth="400.0" /> </items> </SplitPane>
Controller.java
package Aufgabe1.jfx; import javafx.fxml.FXML; import javafx.scene.layout.AnchorPane; public class Controller { @FXML private AnchorPane _canvas ; // called by the FXML loader after the labels declared above are injected: public void initialize() { FunctionCanvas c = new FunctionCanvas(); _canvas.setPrefWidth(400); _canvas.setPrefHeight(300); _canvas.getChildren().add(c); c.drawFunctionCurve(); } }
问题原因及修复方案
1. Canvas未设置有效尺寸
FunctionCanvas继承自Canvas,默认宽高为0,即使调用绘制方法也无法显示内容。修改Controller的initialize方法,让Canvas绑定父容器尺寸并随容器变化:
public void initialize() { FunctionCanvas c = new FunctionCanvas(); // 绑定Canvas尺寸到父AnchorPane c.widthProperty().bind(_canvas.widthProperty()); c.heightProperty().bind(_canvas.heightProperty()); // 设置Canvas填充整个AnchorPane AnchorPane.setTopAnchor(c, 0.0); AnchorPane.setBottomAnchor(c, 0.0); AnchorPane.setLeftAnchor(c, 0.0); AnchorPane.setRightAnchor(c, 0.0); _canvas.getChildren().add(c); // 监听尺寸变化,自动重绘 c.widthProperty().addListener((obs, oldVal, newVal) -> c.drawFunctionCurve()); c.heightProperty().addListener((obs, oldVal, newVal) -> c.drawFunctionCurve()); // 初始绘制 c.drawFunctionCurve(); }
2. 背景色与文字/坐标轴颜色冲突
背景色设为黑色,而文字和坐标轴线条也是深色,导致内容被遮挡。修改FunctionCanvas中的背景色:
private static final Color backGroundColor = Color.WHITE;
3. 曲线绘制方式无效
原代码用strokeLine绘制单个点(起点和终点相同),几乎看不到。修改为连接连续点绘制线段:
gc.setLineWidth(1.5); gc.setStroke(Color.INDIANRED); // 记录前一个点的坐标 double prevY = yZero - ((h / 2) * sinCosFunc(0)); for (int x = 1; x < w; x++) { double currentX = xOffset + x; double currentY = yZero - ((h / 2) * sinCosFunc(x * 2 * Math.PI / w)); // 绘制前一个点到当前点的线段 gc.strokeLine(xOffset + x - 1, prevY, currentX, currentY); prevY = currentY; }
修改完成后,Canvas就能正常显示函数图形了。
内容的提问来源于stack exchange,提问作者Marius
相关产品推荐
相关产品推荐

