JavaFX Canvas
最后修改于 2023 年 10 月 18 日
Canvas
是一个可以使用GraphicsContext
提供的一组图形命令进行绘制的图像。它是一个用于绘画的高级工具。
GraphicsContext
用于使用缓冲区向Canvas
发出绘制调用。
JavaFX 简单线条
在第一个例子中,我们绘制简单的线条。线条是最基本的图形图元。形成一条线需要两个坐标。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class SimpleLinesEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); drawLines(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 250, Color.WHITESMOKE); stage.setTitle("Lines"); stage.setScene(scene); stage.show(); } private void drawLines(GraphicsContext gc) { gc.beginPath(); gc.moveTo(30.5, 30.5); gc.lineTo(150.5, 30.5); gc.lineTo(150.5, 150.5); gc.lineTo(30.5, 30.5); gc.stroke(); } public static void main(String[] args) { launch(args); } }
该示例绘制三条线,形成一个矩形。
var canvas = new Canvas(300, 300);
Canvas
使用指定图像大小的宽度和高度来构造,用于绘制 Canvas 绘图命令。所有绘图操作都被剪裁到该图像的边界。
var gc = canvas.getGraphicsContext2D();
getGraphicsContext2D
返回与 Canvas 关联的GraphicsContext
。
drawLines(gc);
绘制被委托给 drawLines
方法。
gc.beginPath();
线条图元表示为路径元素。beginPath
方法开始一条新路径。
gc.moveTo(30.5, 30.5);
moveTo
方法将当前路径的起始点移动到指定的坐标。
gc.lineTo(150.5, 30.5); gc.lineTo(150.5, 150.5); gc.lineTo(30.5, 30.5);
lineTo
方法将线段添加到当前路径。
gc.stroke();
stroke
方法使用当前的笔画颜色描边路径。

JavaFX 笔画和填充
笔画用于绘制形状的轮廓。填充用于绘制形状的内部。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class StrokeFillEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); doDrawing(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 250, Color.WHITESMOKE); stage.setTitle("Stroke and fill"); stage.setScene(scene); stage.show(); } private void doDrawing(GraphicsContext gc) { gc.setStroke(Color.FORESTGREEN.brighter()); gc.setLineWidth(5); gc.strokeOval(30, 30, 80, 80); gc.setFill(Color.FORESTGREEN); gc.fillOval(130, 30, 80, 80); } public static void main(String[] args) { launch(args); } }
该示例绘制一个圆的轮廓并填充一个圆的内部。
gc.setStroke(Color.FORESTGREEN.brighter());
setStroke
方法设置当前的笔画颜色属性。默认颜色是黑色。该属性由 GraphicsContext
的笔画方法使用。
gc.setLineWidth(5);
setLineWidth
设置当前的线宽。
gc.strokeOval(130, 30, 80, 80);
strokeOval
方法使用当前的笔画颜色描边一个椭圆。
gc.setFill(Color.FORESTGREEN);
setFill
方法设置当前的填充颜色属性。默认颜色是黑色。该属性由 GraphicsContext
的填充方法使用。
gc.fillOval(30, 30, 80, 80);
fillOval
使用当前的填充颜色填充一个椭圆。

JavaFX 颜色
Color
类用于在 JavaFX 中使用颜色。有许多预定义的颜色。可以使用 RGB 或 HSB 颜色模型创建自定义颜色值。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class ColoursEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); drawShapes(gc); root.getChildren().add(canvas); Scene scene = new Scene(root, 280, 200, Color.WHITESMOKE); stage.setTitle("Colours"); stage.setScene(scene); stage.show(); } private void drawShapes(GraphicsContext gc) { gc.setFill(Color.CADETBLUE); gc.fillOval(30, 30, 50, 50); gc.setFill(Color.DARKRED); gc.fillOval(110, 30, 50, 50); gc.setFill(Color.STEELBLUE); gc.fillOval(190, 30, 50, 50); gc.setFill(Color.BURLYWOOD); gc.fillOval(30, 110, 50, 50); gc.setFill(Color.LIGHTSEAGREEN); gc.fillOval(110, 110, 50, 50); gc.setFill(Color.CHOCOLATE); gc.fillOval(190, 110, 50, 50); } public static void main(String[] args) { launch(args); } }
该示例使用预定义的颜色值绘制六个圆圈。
gc.setFill(Color.CADETBLUE);
预定义的 Color.CADETBLUE
颜色被设置为当前填充颜色。
gc.fillOval(30, 30, 50, 50);
一个圆形对象的内部使用当前的填充属性填充。

JavaFx 渐变
在计算机图形学中,渐变是从亮到暗或从一种颜色到另一种颜色的平滑混合。在绘图和绘画程序中,渐变用于创建丰富多彩的背景和特殊效果,以及模拟光线和阴影。有两种类型的渐变:线性渐变和径向渐变。
线性渐变
线性渐变是沿线平滑混合颜色。它由 LinearGradient
类定义。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.paint.CycleMethod; import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Stop; import javafx.stage.Stage; public class LinearGradientEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); doDrawing(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 250, Color.WHITESMOKE); stage.setTitle("Linear gradient"); stage.setScene(scene); stage.show(); } private void doDrawing(GraphicsContext gc) { var stops1 = new Stop[] { new Stop(0.2, Color.BLACK), new Stop(0.5, Color.RED), new Stop(0.8, Color.BLACK)}; var lg1 = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops1); gc.setFill(lg1); gc.fillRect(50, 30, 200, 180); } public static void main(String[] args) { launch(args); } }
在该示例中,我们使用线性渐变填充一个矩形形状。
var stops1 = new Stop[] { new Stop(0.2, Color.BLACK), new Stop(0.5, Color.RED), new Stop(0.8, Color.BLACK)};
我们为渐变定义停止点。它们指定如何在渐变上分配颜色。
var lg1 = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops1);
前四个参数指定绘制渐变的线。第五个参数是比例参数,它设置坐标是否与此渐变填充的形状成比例。第六个参数设置渐变的循环方法。最后一个参数采用停止点。

径向渐变
径向渐变是在一个圆和焦点之间平滑混合颜色或颜色阴影。径向渐变由 RadialGradient
类定义。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.paint.CycleMethod; import javafx.scene.paint.RadialGradient; import javafx.scene.paint.Stop; import javafx.stage.Stage; public class RadialGradientEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); doDrawing(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 250, Color.WHITESMOKE); stage.setTitle("Radial gradient"); stage.setScene(scene); stage.show(); } private void doDrawing(GraphicsContext gc) { var stops1 = new Stop[] { new Stop(0, Color.RED), new Stop(1, Color.BLACK)}; var lg1 = new RadialGradient(0, 0, 0.5, 0.5, 0.8, true, CycleMethod.NO_CYCLE, stops1); gc.setFill(lg1); gc.fillOval(30, 30, 150, 150); } public static void main(String[] args) { launch(args); } }
该示例使用径向渐变填充一个圆。
var stops1 = new Stop[] { new Stop(0, Color.RED), new Stop(1, Color.BLACK)};
我们为渐变定义停止值。
var lg1 = new RadialGradient(0, 0, 0.5, 0.5, 0.8, true, CycleMethod.NO_CYCLE, stops1);
创建径向渐变。前两个参数是焦点角度和焦点距离。接下来的两个参数是渐变圆的中心点的 x 和 y 坐标。第五个参数是定义颜色渐变范围的圆的半径。

JavaFX 形状
矩形、椭圆、弧是基本的几何形状。 GraphicsContext
包含用于绘制这些形状的轮廓和内部的方法。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.ArcType; import javafx.stage.Stage; public class ShapesEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(320, 300); var gc = canvas.getGraphicsContext2D(); drawShapes(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 200, Color.WHITESMOKE); stage.setTitle("Shapes"); stage.setScene(scene); stage.show(); } private void drawShapes(GraphicsContext gc) { gc.setFill(Color.GRAY); gc.fillOval(30, 30, 50, 50); gc.fillOval(110, 30, 80, 50); gc.fillRect(220, 30, 50, 50); gc.fillRoundRect(30, 120, 50, 50, 20, 20); gc.fillArc(110, 120, 60, 60, 45, 180, ArcType.OPEN); gc.fillPolygon(new double[]{220, 270, 220}, new double[]{120, 170, 170}, 3); } public static void main(String[] args) { launch(args); } }
该示例使用图形上下文的填充方法绘制六个不同的形状。
gc.setFill(Color.GRAY);
这些形状用灰色绘制。
gc.fillOval(30, 30, 50, 50); gc.fillOval(110, 30, 80, 50);
fillOval
方法绘制一个圆和一个椭圆。前两个参数是 x 和 y 坐标。第三个和第四个参数是椭圆的宽度和高度。
gc.fillRect(220, 30, 50, 50);
fillRect
使用当前的填充颜色填充一个矩形。
gc.fillRoundRect(30, 120, 50, 50, 20, 20);
fillRoundRect
绘制一个矩形,其角是圆角的。该方法的最后两个参数是矩形角的弧宽和弧高。
gc.fillArc(110, 120, 60, 60, 45, 180, ArcType.OPEN);
fillArc
方法使用当前的填充颜色填充一个弧。最后三个参数是起始角度、角度延伸和闭合类型。
gc.fillPolygon(new double[]{220, 270, 220}, new double[]{120, 170, 170}, 3);
fillPolygon
方法使用当前设置的填充颜色填充具有给定点的多边形。在我们的例子中,它绘制一个直角三角形。第一个参数是一个包含多边形点 x 坐标的数组,第二个参数是一个包含多边形点 y 坐标的数组。最后一个参数是形成多边形的点的数量。

JavaFX 星形
更复杂的形状可以使用 strokePolygon
和 fillPolygon
方法绘制。下一个例子绘制一个星形。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class StarShapeEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(300, 300); var gc = canvas.getGraphicsContext2D(); drawStarShape(gc); root.getChildren().add(canvas); var scene = new Scene(root, 300, 250, Color.WHITESMOKE); stage.setTitle("Star"); stage.setScene(scene); stage.show(); } private void drawStarShape(GraphicsContext gc) { double[] xpoints = {10, 85, 110, 135, 210, 160, 170, 110, 50, 60}; double[] ypoints = {85, 75, 10, 75, 85, 125, 190, 150, 190, 125}; gc.strokePolygon(xpoints, ypoints, xpoints.length); } public static void main(String[] args) { launch(args); } }
该示例绘制一个星形的轮廓。该形状由十个坐标组成。
double[] xpoints = {10, 85, 110, 135, 210, 160, 170, 110, 50, 60}; double[] ypoints = {85, 75, 10, 75, 85, 125, 190, 150, 190, 125};
这些是形状的 x 和 y 坐标。
gc.strokePolygon(xpoints, ypoints, xpoints.length);
该形状使用 strokePolygon
方法绘制。

JavaFX 透明矩形
透明度是能够看穿材料的质量。在计算机图形学中,我们可以使用 alpha 合成来实现透明效果。Alpha 合成是将图像与背景组合以创建部分透明外观的过程。
package com.zetcode; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class TransparentRectanglesEx extends Application { @Override public void start(Stage stage) { initUI(stage); } private void initUI(Stage stage) { var root = new Pane(); var canvas = new Canvas(600, 300); var gc = canvas.getGraphicsContext2D(); drawRectangles(gc); root.getChildren().add(canvas); var scene = new Scene(root, 600, 100, Color.WHITESMOKE); stage.setTitle("Transparent rectangles"); stage.setScene(scene); stage.show(); } private void drawRectangles(GraphicsContext gc) { for (int i = 1; i <= 10; i++) { float alpha = i * 0.1f; gc.setFill(Color.FORESTGREEN); gc.setGlobalAlpha(alpha); gc.fillRect(50 * i, 20, 40, 40); } } public static void main(String[] args) { launch(args); } }
该示例绘制了十个具有不同透明度级别的矩形。
float alpha = i * 0.1f;
alpha 值在每个 for
循环中计算。
gc.setGlobalAlpha(alpha);
setGlobalAlpha
方法设置当前状态的全局 alpha 值。

在本章中,我们在 Canvas
节点上执行了绘制操作。