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

如何让JavaFX Canvas的fillText旋转效果与Node Text保持一致

JavaFX Canvas fillText 旋转匹配 Text Node 行为的解决方案

Text Node的rotate是围绕自身边界框中心旋转的,而Canvas的rotate默认围绕坐标系原点(0,0)旋转,直接调用会导致文本旋转中心错位。要实现完全一致的效果,需要通过坐标变换对齐旋转中心,步骤如下:

  • 计算待绘制文本的边界框中心坐标
  • 将Canvas坐标系原点平移到该中心
  • 执行旋转操作
  • 平移回文本绘制起点相对于中心的偏移量,确保文本绘制在初始目标位置
  • 绘制文本后恢复Canvas的变换状态,避免影响后续绘制

完整代码示例

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontMetrics;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class RotatedTextComparison extends Application {
    private static final String TEXT = "Hello Rotated";
    private static final double ROTATE_ANGLE = 45;
    private static final Font FONT = Font.font(24);

    @Override
    public void start(Stage stage) {
        // 左侧标准Text Node(旋转基准)
        Text textNode = new Text(TEXT);
        textNode.setFont(FONT);
        textNode.setFill(Color.BLUE);
        textNode.setRotate(ROTATE_ANGLE);

        // 右侧Canvas绘制旋转文本
        Canvas canvas = new Canvas(300, 200);
        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.setFont(FONT);
        gc.setFill(Color.RED);

        drawRotatedText(gc, TEXT, 50, 100, ROTATE_ANGLE);

        HBox root = new HBox(20, textNode, canvas);
        root.setStyle("-fx-padding: 20; -fx-background-color: #f0f0f0;");
        stage.setScene(new Scene(root));
        stage.setTitle("Text Rotation Comparison");
        stage.show();
    }

    private void drawRotatedText(GraphicsContext gc, String text, double x, double y, double angle) {
        // 获取文本精确度量信息
        FontMetrics metrics = gc.getFontMetrics();
        double textWidth = metrics.computeStringWidth(text);
        double textHeight = metrics.getHeight();
        // 计算文本边界框的中心坐标(基于绘制起点x,y)
        double centerX = x + textWidth / 2;
        double centerY = y - metrics.getDescent() + textHeight / 2;

        gc.save(); // 保存当前变换状态,隔离本次操作

        // 1. 平移坐标系原点到文本中心
        gc.translate(centerX, centerY);
        // 2. 执行旋转
        gc.rotate(angle);
        // 3. 平移回文本绘制起点的偏移量,确保文本位置正确
        gc.translate(-centerX, -centerY);

        // 绘制目标文本
        gc.fillText(text, x, y);

        gc.restore(); // 恢复变换状态,不影响后续Canvas绘制
    }

    public static void main(String[] args) {
        launch(args);
    }
}

关键细节说明

  • 使用FontMetrics获取文本的精确尺寸(包括下沉量descent),确保旋转中心计算和Text Node的边界框中心完全一致
  • save()和restore()方法用来隔离变换操作,避免本次旋转影响Canvas上的其他绘制内容
  • 变换顺序不可颠倒:必须先平移到中心,再旋转,最后平移回偏移,才能保证旋转中心正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:57:33