如何在javafx.scene.Canvas中直接绘制Ikonli的FontIcon(kordamp 12.3.1)
在JavaFX Canvas中绘制Ikonli FontIcon的问题
我需要在javafx.scene.Canvas中直接绘制Ikonli的FontIcon(使用kordamp 12.3.1版本),目标是让左侧的图标显示在右侧的Canvas上。目前我通过快照方式尝试实现,但显示效果不正确。我认为存在其他实现方式,比如获取SVG,但尚未找到基于Ikonli的可行方案。
效果截图:
当前代码:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.SnapshotParameters; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.image.Image; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.stage.Stage; import org.kordamp.ikonli.fontawesome5.FontAwesomeSolid; import org.kordamp.ikonli.javafx.FontIcon; public class IkonliCanvas extends Application { @Override public void start(Stage primaryStage) { // 创建Canvas Canvas canvas = new Canvas(100, 400 ); GraphicsContext gc = canvas.getGraphicsContext2D(); Pane pcanvas = new Pane(); pcanvas.getChildren().add(canvas); FontIcon fi = new FontIcon(FontAwesomeSolid.APPLE_ALT); fi.setIconSize(30); Image snapshot = fi.snapshot(new SnapshotParameters(), null); gc.drawImage(snapshot, 40,100); Pane p = new Pane(); p.getChildren().add(fi); p.setPrefWidth(100); fi.setLayoutX(40); fi.setLayoutY(100); BorderPane bp = new BorderPane(); bp.setLeft(p); bp.setCenter(pcanvas); Scene scene = new Scene(bp, 220,400); primaryStage.setScene(scene); primaryStage.setTitle("Canvas Ikonli"); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
解决方案
方法一:修复快照渲染问题
快照失效的核心原因是FontIcon还未完成布局和渲染就被执行快照操作。只需将快照逻辑延迟到JavaFX渲染队列的下一帧,确保图标先完成渲染:
修改代码中的快照部分:
// 原快照代码替换为以下内容 fi.applyCss(); fi.layout(); // 延迟到下一帧执行快照 Platform.runLater(() -> { Image snapshot = fi.snapshot(new SnapshotParameters(), null); gc.drawImage(snapshot, 40, 100); });
注意需要导入javafx.application.Platform包。
方法二:直接绘制SVG路径(更高效)
Ikonli的FontIcon本质是矢量图形,可直接获取其SVG路径数据,通过Canvas的GraphicsContext绘制,避免快照的性能开销:
示例代码:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.SVGPath; import javafx.stage.Stage; import org.kordamp.ikonli.fontawesome5.FontAwesomeSolid; import org.kordamp.ikonli.javafx.FontIcon; public class IkonliCanvas extends Application { @Override public void start(Stage primaryStage) { Canvas canvas = new Canvas(100, 400); GraphicsContext gc = canvas.getGraphicsContext2D(); Pane pcanvas = new Pane(canvas); // 获取FontIcon的SVG路径数据 FontIcon fi = new FontIcon(FontAwesomeSolid.APPLE_ALT); fi.setIconSize(30); String svgPathData = fi.getIcon().getDescription(); // 初始化SVGPath并设置路径内容 SVGPath svgPath = new SVGPath(); svgPath.setContent(svgPathData); // 设置绘制参数 gc.setFill(Color.BLACK); // 对应FontIcon的iconColor属性 gc.translate(40, 100); // 图标位置偏移 // 按图标大小缩放,Ikonli默认基准大小为16px gc.scale(fi.getIconSize() / 16.0, fi.getIconSize() / 16.0); // 在Canvas上绘制路径 gc.fill(svgPath); // 左侧显示原图标用于对比 Pane p = new Pane(fi); p.setPrefWidth(100); fi.setLayoutX(40); fi.setLayoutY(100); BorderPane bp = new BorderPane(); bp.setLeft(p); bp.setCenter(pcanvas); Scene scene = new Scene(bp, 220, 400); primaryStage.setScene(scene); primaryStage.setTitle("Canvas Ikonli"); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
说明:
fi.getIcon().getDescription()返回的是图标原始SVG路径字符串,FontAwesome系列图标均支持该API- 缩放比例基于Ikonli默认的16px基准大小,可根据实际需求调整
- 通过
gc.setFill()可自定义图标颜色,效果与FontIcon的iconColor一致
内容的提问来源于stack exchange,提问作者tretonis
相关产品推荐
相关产品推荐

