Обрезка JavaFX создает эффект "лотерейного чека"
Я начал играть с JavaFX
GraphicsContext
, Особенно мне интересна часть отсечения.
поэтому я попытался создать некоторую графику и создать для нее обтравочную маску (простой прямоугольник, который перемещается)
но я заметил странное поведение (не уверен, что это ошибка или неправильное использование кода)
ниже вы можете найти пример приложения, чтобы показать проблему.
Описание того, что я ожидал от своего кода: белый холст с прямоугольником 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)
блок, вы видите поведение, я думаю, вы ожидаете.