JavaFX 裁剪产生 'lottery scratch ticket' -Effect

标签 java canvas javafx graphicscontext

我开始使用 JavaFX GraphicsContext。 尤其是剪辑部分对我来说很有趣。

所以我尝试创建一些图形并为其创建一个剪贴蒙版(一个简单的矩形,可以四处移动)

但我注意到它有一些奇怪的行为(不确定这是一个错误还是由于代码使用不正确)

您可以在下面找到一个示例应用程序来显示该问题。

描述我对代码的期望: 白色 Canvas ,带有带有文本的洋红色矩形,仅在洋红色上方可见(尽管它是跨过绘制的)

实际上,这正是您首先看到的!

当您移动应用程序窗口时,洋红色矩形会四处移动(如预期)!但是古董白色填充变得可见(这是我从未预料到的),并且任何曾经被洋红色覆盖的区域现在都可见(没有剪切)

ANTIQUEWHITE 和 MAGENTA 的东西,用来让问题变得更加明显。由于整个 Canvas 在开始时就被清除,并且只完成了一次剪辑,因此重新绘制(或在旧绘图上绘制)应该不是问题

启动应用程序并移动它以查看“彩票刮刮票”效果

public class ClippingExampleApp extends Application {

    private boolean clip = true;
    private static Bounds clippingArea = new BoundingBox(100, 50, 300, 300);

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Clipping Test App");
        primaryStage.setX(100);
        primaryStage.setY(50);

        Group root = new Group();
        Canvas canvas = new Canvas(640, 480);
        root.getChildren().add(canvas);
        primaryStage.setScene(new Scene(root));

        ChangeListener<Number> updateBounds = new ChangeListener<Number>() {

            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
                clippingArea = new BoundingBox(primaryStage.getX(), primaryStage.getY(), 300, 300);
                draw(canvas, clip);
            }
        };
        primaryStage.yProperty().addListener(updateBounds);
        primaryStage.xProperty().addListener(updateBounds);
        primaryStage.widthProperty().addListener(updateBounds);
        primaryStage.heightProperty().addListener(updateBounds);

        primaryStage.show();
        clippingArea = new BoundingBox(primaryStage.getX(), primaryStage.getY(), 300, 300);
        draw(canvas, clip);
    }

    private static void draw(Canvas canvas, boolean clip) {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        // CLEAR THE COMPLETE CANVAS
        gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        gc.save();
        if (clip) {
            // clipping rect
            gc.rect(clippingArea.getMinX(), clippingArea.getMinY(), clippingArea.getWidth(), clippingArea.getHeight());
            gc.clip();

            // fill the whole background (this should only affect the clipped
            // area 
            gc.setFill(Color.ANTIQUEWHITE);
            gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
            // this should overlap the Color.ANTIQUEWHITE - so no ANTIQUEWHITE is visible
            gc.setFill(Color.MAGENTA);
            gc.fillRect(clippingArea.getMinX(), clippingArea.getMinY(), clippingArea.getWidth(), clippingArea.getHeight());

            // finally fill the text, which sould only be visible where the magenta rect is...
            String text = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";
            gc.setFill(Color.BLACK);
            gc.fillText(text, 50, 100);
        }
        gc.restore();
    }
}

最佳答案

来自documentation for restore() :

Note that the current path is not restored.

因此,您进行的所有 gc.rect() 调用都会累积到用作剪辑的单个路径中。

如果添加

gc.beginPath();

清除 if (clip) block 开头的路径,您会看到我认为您期望的行为。

关于JavaFX 裁剪产生 'lottery scratch ticket' -Effect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46847276/

相关文章:

java - 替换 JavaFX 中的列排序

java - 如何映射 JavaFX 可观察值的值?

JavaFX ScrollPane如何设置透明背景

java - 在使用 Java 中的正则表达式从日志中提取表达式时需要帮助

java - Cloudsim和Java引用返回问题

java - 如何将 FX Controller 与主应用程序连接

canvas - jquery旋钮角度渐变

android - 用 android drawLines 画很多线

java - 如何告诉spring使用log4j2打印日志消息?

javascript - 宽高比为 16 :9 and 4:3/Vertically centering the canvas when the aspect ratio is 4:3 的 Canvas 是否有任何通用尺寸