JavaFX GraphicsContext clearRect不适用于剪辑蒙版

问题描述 投票:0回答:3

GraphicsContext的clearRect方法的文档指出,它使用了当前剪辑,但是当前不适用于我。考虑:

GraphicsContext context = canvas.getGraphicsContext2D();
context.beginPath();
context.rect(0,0,100,100); //Set the current path to a rectangle
context.stroke(); //Highlights where the current path is
context.clip();   //Intersect current clip with rectangle
context.fillOval(80, 80, 40, 40); //This correctly draws the oval clipped
context.clearRect(0,0,100,100); //This does nothing at all

上面的代码正确设置了剪贴蒙版,这可以通过fillOval正常工作这一事实来证明,但是clearRect却不起作用(尽管没有context.clip()可以正常工作)。为什么是这样?

((请注意,我特别需要剪贴蒙板才能工作,稍后我打算将其设置为特定形状以擦除非矩形形状。)

-编辑-

要清楚,clearRect实际上不执行任何操作,甚至不会擦除椭圆。我意识到它不会擦除描边的矩形,但这不是我所关心的。

-编辑2-

更新到最新的JDK已部分地解决了该问题。上面的代码现在可以正常工作。但是,使用非矩形夹罩仍然存在相同的问题。例如

GraphicsContext context = canvas.getGraphicsContext2D();
context.beginPath();
context.arc(50, 50, 40, 40, 0, 360); // Make a circular clip mask
context.closePath();
context.clip();
context.fillRect(0, 0, 200, 200); //Draw a circle clipped correctly, shows clip mask is working
context.clearRect(0, 0, 200, 200); //Does nothing

我意识到我可以使用保存和还原来恢复矩形剪贴蒙版,然后clearRect可以工作。但是,我希望能够以非矩形形状擦除。

用于重现此内容的完整代码是(通过在eclipse中创建一个新的JavaFX项目并添加上述行来创建的:]

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = new BorderPane();
            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();

            Canvas canvas = new Canvas(500, 500);
            root.getChildren().add(canvas);

            GraphicsContext context = canvas.getGraphicsContext2D();
            context.beginPath();
            context.arc(50, 50, 40, 40, 0, 360);
            context.closePath();
            context.clip();
            context.fillRect(0, 0, 200, 200);
            context.clearRect(0, 0, 200, 200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

这应该显示一个空白屏幕,但是圆圈没有被清除。

java javafx javafx-8
3个回答
0
投票

该代码在带有JavaFX 8u40的Windows 7上运行正常。

您应该做的是提供一个MCVE。没有人可能猜出您对GraphicsContext所做的其他事情。可能缺少saverestore,而没有。顺便说一下,您的代码缺少closePath()


编辑前回答:

您面临的问题是JavaFX的界线。请查看Node类的文档:

[在设备像素级别,整数坐标映射到角落像素和像素中心之间出现裂缝整数像素位置之间的中点。因为所有的协调值用浮点数指定,坐标可以精确地指向这些角(当浮点值具有精确整数值)或像素上的任何位置。例如,一个(0.5,0.5)的坐标将指向左上方的中心舞台上的像素。同样,尺寸为(0,0)的矩形的10乘10会从左上角的左上角开始舞台上的像素到第10个像素的右下角第十条扫描线。最后一个像素的像素中心矩形将位于坐标(9.5,9.5)。

这就是为什么您的右侧和底部都有一条细线。这些行不是crisp

我建议您将矩形移到中心,并使用fill方法使它对您更可见。

您的代码没有clearRect:

enter image description here

您的带有clearRect的代码:

enter image description here


0
投票

根据Edit 2,此行为似乎是一个错误。总之,当设置了非矩形剪辑时,clearRect无效。 (如果即使使用矩形剪辑也无法使用它,请更新到最新的JDK。)我已经为此提交了一个错误报告。


0
投票

虽然我同意应解决此问题,但面对事实并非如此,但我已经提出了至少可以满足我的特定需求的解决方案。

这是一种使用GraphicsContext基于SVGPath清除区域的方法。

private void clearPath(GraphicsContext gc, SVGPath path) {
        int xstart = (int) path.getLayoutX();
        int xend = (int) (xstart + path.getLayoutBounds().getMaxX());
        int ystart = (int) path.getLayoutY();
        int yend = (int) (ystart + path.getLayoutBounds().getMaxY());

        PixelWriter pw = gc.getPixelWriter();
        for (int x = xstart; x <= xend; x++) {
            for (int y = ystart; y <= yend; y++) {
                if(path.contains(new Point2D(x, y))) {
                    pw.setColor(x, y, Color.TRANSPARENT);
                }
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.