Обрезка JavaFX создает эффект "лотерейного чека"

Я начал играть с JavaFXGraphicsContext, Особенно мне интересна часть отсечения.

поэтому я попытался создать некоторую графику и создать для нее обтравочную маску (простой прямоугольник, который перемещается)

но я заметил странное поведение (не уверен, что это ошибка или неправильное использование кода)

ниже вы можете найти пример приложения, чтобы показать проблему.

Описание того, что я ожидал от своего кода: белый холст с прямоугольником MAGENTA с текстом, который виден только над пурпурным (хотя он нарисован поперек)

на самом деле это именно то, что вы видите в первую очередь!

когда вы перемещаете окно приложения, прямоугольник MAGENTA перемещается (как и ожидалось)! но заливка ANTIQUEWHITE становится видимой (чего я никогда не ожидал), и теперь видна любая область, которая когда-либо была покрыта MAGENTA (без отсечения)

Материал ANTIQUEWHITE и MAGENTA используется, чтобы сделать его более очевидным, что-то идет не так. так как весь холст очищается в начале и выполняется только одно вырезание, это не должно быть проблемой при перерисовке (или закрашивании старого рисунка)

запустите приложение и переместите его, чтобы увидеть эффект "лотерейного билета"

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();
    }
}

1 ответ

Решение

Из документации дляrestore():

Обратите внимание, что текущий путь не восстанавливается.

Так что все gc.rect() звонки, которые вы делаете, накапливаются в один путь, который используется в качестве клипа.

Если вы добавите

gc.beginPath();

очистить путь в начале if (clip) блок, вы видите поведение, я думаю, вы ожидаете.

Другие вопросы по тегам