当前位置: 首页 > 知识库问答 >
问题:

JavaFX画布:填充由多个几何图形组成的闭合路径

陈琪
2023-03-14

我想绘制和填充由2个弧和2条线组成的路径与一个特定的颜色。我需要使用JavaFX中的画布,因为我需要绘制更多的画布。问题是,我创建的路径甚至没有绘制或填充。我想要的是这个

但我的代码产生了

正如你可能注意到的,这个弧线在左边和右边比在中间要细。只是使用一个简单的弧与一个ceratin的笔画宽度是不幸的不是一个选择对我。

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;

public final class CanvasTest extends Application {

    private static final int WIDTH = 400;
    private static final int HEIGHT = 300;
    private static final int RADIUS = 250;

    private static final int BRICK_HEIGHT = 15;
    private static final int RADIUSHALF = RADIUS / 2;
    private static GraphicsContext gc;

    @Override
    public void start(Stage stage) {
        final Group root = new Group();
        final Scene scene = new Scene(root, WIDTH, HEIGHT);
        final Canvas can = new Canvas(WIDTH, HEIGHT);
        gc = can.getGraphicsContext2D();

        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, WIDTH, HEIGHT);

        drawArc(WIDTH / 2, HEIGHT / 2);

        root.getChildren().add(can);
        stage.setScene(scene);
        stage.show();
    }

    private void drawArc(final int posX, final int posY) {
        gc.setStroke(Color.WHITE);
        gc.setLineWidth(1);
        gc.setFill(Color.WHITE);

        final double newRadius = RADIUSHALF - BRICK_HEIGHT;
        final double yOffsetLowerArc = Math.cos(Math.toRadians(45)) * newRadius;
        final double xOffsetLowerArc = Math.sin(Math.toRadians(45)) * newRadius;
        final double newAngleLowerArc = Math.toDegrees(Math.atan2(xOffsetLowerArc, yOffsetLowerArc + BRICK_HEIGHT));
        final double xOffsetUpperArc = Math.cos(Math.toRadians(45)) * RADIUSHALF;
        final double yOffsetUpperArc = Math.sin(Math.toRadians(45)) * RADIUSHALF;
        final double yOffsetNewLowerArc = Math.cos(Math.toRadians(newAngleLowerArc)) * RADIUSHALF;
        final double xOffsetNewLowerArc = Math.sin(Math.toRadians(newAngleLowerArc)) * RADIUSHALF;

        // this code produces the un-filled custom arc
        // gc.strokeArc(posX - RADIUSHALF, posY - RADIUSHALF, RADIUS, RADIUS, 45, 90, ArcType.OPEN);
        // gc.strokeArc(posX - RADIUSHALF, posY - RADIUSHALF + BRICK_HEIGHT, RADIUS, RADIUS, 90 - newAngleLowerArc, 2 * newAngleLowerArc, ArcType.OPEN);
        // gc.strokeLine(posX - xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc, posX - xOffsetUpperArc, posY - yOffsetUpperArc);
        // gc.strokeLine(posX + xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc, posX + xOffsetUpperArc, posY - yOffsetUpperArc);

        gc.beginPath();
        gc.arc(posX - RADIUSHALF, posY - RADIUSHALF, RADIUS, RADIUS, 45, 90/*, ArcType.OPEN*/);
        gc.arc(posX - RADIUSHALF, posY - RADIUSHALF + BRICK_HEIGHT, RADIUS, RADIUS, 90 - newAngleLowerArc, 2 * newAngleLowerArc/*, ArcType.OPEN*/);
        gc.moveTo(posX + xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc);
        gc.lineTo(posX + xOffsetUpperArc, posY - yOffsetUpperArc);
        gc.moveTo(posX - xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc);
        gc.lineTo(posX - xOffsetUpperArc, posY - yOffsetUpperArc);
        gc.closePath();
        gc.fill();
    }

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

共有1个答案

常炯
2023-03-14

您的代码存在一些问题。GraphicsContext.arc的参数与GraphicsContext.Strokearc不同。

strokeArc(double x,
          double y,
          double w,
          double h,
          double startAngle,
          double arcExtent,
          ArcType closure)
arc(double centerX,
    double centerY,
    double radiusX,
    double radiusY,
    double startAngle,
    double length)

区别在于:strokearc绘制的弧是位于点(x,y)处的矩形中椭圆的一部分,具有给定的宽度高度。然而,arc构造了一条路径,该路径是以(centerX,centerY)为中心的椭圆形的一部分,具有半径radiusxradiusy。要获得arc的适当参数,可以使用以下公式:

centerX = (x+w)/2
centerY = (y+h)/2
radiusX = w/2
radiusY = h/2

此外,您不需要调用moveto来构建路径。2个弧线足以构成路径。还要确保使用不同方向的弧线(一个顺时针,一个逆时针)来连接弧线的最近端:

gc.beginPath();
gc.arc(posX, posY, RADIUSHALF, RADIUSHALF, 45, 90);

// next arc in opposite direction
gc.arc(posX, posY + BRICK_HEIGHT, RADIUSHALF, RADIUSHALF, 90 + newAngleLowerArc, -2 * newAngleLowerArc);
gc.closePath();

gc.fill();
 类似资料:
  • 我想在一个组合框中填充一些数据。这很好。但是,我想动态地改变组合框中的数据。 目前我有一个表,在组合框中,我在表列中显示数据的唯一值。现在,表数据存储在静态可观察列表变量中。我想根据表中显示的数据更改组合框中的数据。也就是说,如果存储表数据的静态可观察列表发生更改,我希望在没有手动干预的情况下更改组合框数据。 如果没有单独的静态变量用于组合框,这是否可能?

  • 我无法填充从场景生成器创建的JavaFX组合框。虽然我已经搜索过了,但我找不到解决这个错误的方法。 下面的例子都不管用。 帮助将不胜感激。

  • 我可以在Google地图中绘制多边形。现在,当我在地图上绘制完该区域的多边形时,我想用相同的图标填充该多边形。我可以用颜色填充多边形,但我想用边框有一些填充和图标之间有一些指定空间的图标填充它。我该怎么做?

  • 我有一个箭头头的路径,我想做一个颜色过渡动画,从左到右。 我已经为线和箭头做了这件事,但它似乎不是同步的。我希望线和箭头都过渡颜色无缝。 CSS

  • 我正在查询Sql Server并返回一个List-我想使用此List作为我的组合框的源。下面是我正在使用的代码,它运行时没有错误,但我的组合框始终为空并且从不填充。这里有什么不正确的? 主要的Java语言 样品fxml

  • 我试图避免将一大堆数字硬编码到我的JavaFX ComboBox中,但我不知道有任何其他方法可以做到这一点。目前我正在这样做: 然而,我的目标是调用一个方法,该方法将生成一个达到某个指定上限(例如50)的数字列表。我尝试了以下方法,但它只是添加了最后一个,而不是全部50: