自动调整画布,以填补封装的父 [英] Automatically resize Canvas to fill the enclosing Parent
问题描述
我最近想创建JavaFX中动画背景,类似于这里看到 Swing的例子。我用了一个 帆布
上绘制,如图的的与画布API 的,和的 AnimationTimer
为绘图循环,如的 动画基础 的。不幸的是,我不知道如何来调整画布
自动封闭舞台
调整大小。什么是好办法?
I recently wanted to create an animated background in JavaFX, similar to the Swing example seen here. I used a Canvas
on which to draw, as shown in Working with the Canvas API, and an AnimationTimer
for the drawing loop, as shown in Animation Basics. Unfortunately, I'm not sure how to resize the Canvas
automatically as the enclosing Stage
is resized. What is a good approach?
推荐答案
在下面的例子中,Static Nested Class和 CanvasPane
包装的 画布
在 面板
并覆盖 layoutChildren()
来使画布尺寸封装匹配面板
。需要注意的是画布
收益假
来自的 isResizable()
,所以家长不能调整它的布局中,与面板
不执行超出调整可调整大小的孩子他们的preferred尺寸的布局。在宽度
和高度
用于构造画布成为其初始大小。类似的方法在的乐团使用EM> 粒子模拟,<一个href=\"http://grep$c$c.com/file/repo1.maven.org/maven2/org.jbundle.javafx.example/org.jbundle.javafx.example.ensemble/0.9.0/ensemble/samples/canvas/FireworksSample.java#FireworksSample.SanFranciscoFireworks.layoutChildren%28%29\"相对=nofollow> Fireworks.java
,缩放背景图像,同时保留其长宽比。
In the example below, the static nested class CanvasPane
wraps an instance of Canvas
in a Pane
and overrides layoutChildren()
to make the canvas dimensions match the enclosing Pane
. Note that Canvas
returns false
from isResizable()
, so "the parent cannot resize it during layout," and Pane
"does not perform layout beyond resizing resizable children to their preferred sizes." The width
and height
used to construct the canvas become its initial size. A similar approach is used in the Ensemble particle simulation, Fireworks.java
, to scale a background image while retaining its aspect ratio.
顺便说一句,使用完全饱和的颜色比原来的注意区别。
As an aside, note the difference from using fully saturated colors compared to the original.
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* @see http://stackoverflow.com/a/31761362/230513
* @see http://stackoverflow.com/a/8616169/230513
*/
public class Baubles extends Application {
private static final int MAX = 64;
private static final double WIDTH = 640;
private static final double HEIGHT = 480;
private static final Random RND = new Random();
private final Queue<Bauble> queue = new LinkedList<>();
private Canvas canvas;
@Override
public void start(Stage stage) {
CanvasPane canvasPane = new CanvasPane(WIDTH, HEIGHT);
canvas = canvasPane.getCanvas();
BorderPane root = new BorderPane(canvasPane);
CheckBox cb = new CheckBox("Animate");
cb.setSelected(true);
root.setBottom(cb);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
for (int i = 0; i < MAX; i++) {
queue.add(randomBauble());
}
AnimationTimer loop = new AnimationTimer() {
@Override
public void handle(long now) {
GraphicsContext g = canvas.getGraphicsContext2D();
g.setFill(Color.BLACK);
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
for (Bauble b : queue) {
g.setFill(b.c);
g.fillOval(b.x, b.y, b.d, b.d);
}
queue.add(randomBauble());
queue.remove();
}
};
loop.start();
cb.selectedProperty().addListener((Observable o) -> {
if (cb.isSelected()) {
loop.start();
} else {
loop.stop();
}
});
}
private static class Bauble {
private final double x, y, d;
private final Color c;
public Bauble(double x, double y, double r, Color c) {
this.x = x - r;
this.y = y - r;
this.d = 2 * r;
this.c = c;
}
}
private Bauble randomBauble() {
double x = RND.nextDouble() * canvas.getWidth();
double y = RND.nextDouble() * canvas.getHeight();
double r = RND.nextDouble() * MAX + MAX / 2;
Color c = Color.hsb(RND.nextDouble() * 360, 1, 1, 0.75);
return new Bauble(x, y, r, c);
}
private static class CanvasPane extends Pane {
private final Canvas canvas;
public CanvasPane(double width, double height) {
canvas = new Canvas(width, height);
getChildren().add(canvas);
}
public Canvas getCanvas() {
return canvas;
}
@Override
protected void layoutChildren() {
final double x = snappedLeftInset();
final double y = snappedTopInset();
final double w = snapSize(getWidth()) - x - snappedRightInset();
final double h = snapSize(getHeight()) - y - snappedBottomInset();
canvas.setLayoutX(x);
canvas.setLayoutY(y);
canvas.setWidth(w);
canvas.setHeight(h);
}
}
public static void main(String[] args) {
launch(args);
}
}
这篇关于自动调整画布,以填补封装的父的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!