JavaFX 裁剪产生 'lottery scratch ticket' 效果
JavaFX clipping produces a 'lottery scratch ticket'-Effect
我开始玩 JavaFX
GraphicsContext
。
尤其是剪辑部分我很感兴趣。
所以我尝试创建一些图形并为其创建剪贴蒙版(一个简单的矩形,四处移动)
但我注意到它有一些奇怪的行为(不确定这是错误还是由于代码使用不正确)
您可以在下面找到一个示例应用程序来说明问题。
描述我对代码的期望:
白色 Canvas 带有带有文本的洋红色矩形,仅在洋红色上方可见(尽管它被绘制成横跨)
其实这就是你看到的首先!
当您移动应用程序 window 时,MAGENTA 矩形四处移动(如预期的那样)!但是 ANTIQUEWHITE 填充变得可见(这是我从未预料到的)并且任何曾经被 MAGENTA 覆盖的区域现在都可见(没有剪裁)
ANTIQUEWHITE 和 MAGENTA 的东西,用来让事情变得更明显。由于整个 canvas 在开始时被清除并且只完成了一次剪裁,因此重绘(或在旧图上绘画)应该没有问题
启动应用程序并移动它以查看 'lottery scratch ticket' 效果
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)
块开头的路径,您会看到我认为您期望的行为。
我开始玩 JavaFX
GraphicsContext
。
尤其是剪辑部分我很感兴趣。
所以我尝试创建一些图形并为其创建剪贴蒙版(一个简单的矩形,四处移动)
但我注意到它有一些奇怪的行为(不确定这是错误还是由于代码使用不正确)
您可以在下面找到一个示例应用程序来说明问题。
描述我对代码的期望: 白色 Canvas 带有带有文本的洋红色矩形,仅在洋红色上方可见(尽管它被绘制成横跨)
其实这就是你看到的首先!
当您移动应用程序 window 时,MAGENTA 矩形四处移动(如预期的那样)!但是 ANTIQUEWHITE 填充变得可见(这是我从未预料到的)并且任何曾经被 MAGENTA 覆盖的区域现在都可见(没有剪裁)
ANTIQUEWHITE 和 MAGENTA 的东西,用来让事情变得更明显。由于整个 canvas 在开始时被清除并且只完成了一次剪裁,因此重绘(或在旧图上绘画)应该没有问题
启动应用程序并移动它以查看 'lottery scratch ticket' 效果
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)
块开头的路径,您会看到我认为您期望的行为。