JavaFX Canvas.setScaleX/Y(2) 未缩放到两倍大小
JavaFX Canvas.setScaleX/Y(2) not scaling to twice the size
也许我误解了一些基本的东西,但我正在试验 JavaFX,我很困惑为什么缩放 Canvas(使用 .setScaleX/Y)值为 2 不会导致 canvas 大两倍 width/height.
相关代码是这样的:(此时我没有使用任何 .fxml)
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
canvas.setScaleX(2);
canvas.setScaleY(2);
pane.getChildren().add(canvas);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
这导致 canvas 大约占 window 的 2/3(根据 width/heighth,而不是面积)。使用 3 的比例会使它填满整个 window(边缘有一个像素间隙),我不明白为什么。我查看了文档,但似乎缩放因子 2 应该导致尺寸的两倍。
编辑:
因此,根据下面的建议,将 canvas 翻译成 width/height 的一半可以解决问题。但是它在 StackPane 中居中也是如此,所以我不明白为什么 AnchorPane 在缩放后确实是 200x200 时不会通过它的 top/left 边缘来锚定它,就好像它是通过它的 100x100 边缘来锚定它一样.但是,如果 Canvas 是 100x100,那么如果只是在 StackPane 中居中,它是如何绘制到这些边界之外的呢?
编辑2:
通过一些试验,我认为我确认 AnchorPane 将 Canvas 定位为“好像”它仍然是 100x100。因此,通过将顶部和左侧锚点设置为 50,我可以获得与平移 50 或在 StackPane 中居中相同的结果。
但这意味着 Canvas 实际上是在其“边缘”之外“绘制”。这肯定不对吧?
您已经将 canvas 添加到窗格中,尝试在 pane.getChildren().add(canvas)
.
之前应用 .setScaleX/Y
您在原始编辑中添加的信息 post 给出了问题的大部分答案。
首先请注意,scaleX
和 scaleY
围绕其中心缩放节点。来自 documentation:“定义坐标沿此节点的 X 轴围绕对象中心缩放的系数。”
其次,请注意,在该节点的布局计算中不会考虑应用于该节点的转换。来自 layout documentation(参见“视觉边界与布局边界”部分):
So for example ... if a ScaleTransition
is used to pulse the size of a
button, that pulse animation will not disturb layout around that
button. If an application wishes to have the effect, clip, or
transform factored into the layout of a node, it should wrap that node
in a Group
.
文档中引用的最后一句话是指 Group
的布局边界包括应用于组的子项(但不应用于组本身)的任何转换。
要可视化正在发生的事情,请从 100x100 canvas 开始。布局忽略了缩放,因此您可以将其可视化为在 应用缩放之前将 canvas 锚定到锚窗格的左上角 。然后 canvas 围绕其中心缩放,将所有四个角从两个维度的中心推开 50 像素。因此,锚窗格坐标系中 canvas 的边界是从 (-50, -50)
到 (150, 150)
。您可以通过添加
来验证这一点
System.out.println(canvas.getBoundsInParent());
舞台演出后
有两种解决方法。一种是将 canvas 包裹在 Group
中。 Group
的布局边界将考虑 canvas:
上的缩放比例
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
canvas.setScaleX(2);
canvas.setScaleY(2);
Group group = new Group(canvas);
AnchorPane.setTopAnchor(group, 0.0);
AnchorPane.setLeftAnchor(group, 0.0);
pane.getChildren().add(group);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
另一种解决方案是应用缩放 canvas 左上角的变换:
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
Scale scale = new Scale(2,2);
scale.setPivotX(0);
scale.setPivotY(0);
canvas.getTransforms().add(scale);
pane.getChildren().add(canvas);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
也许我误解了一些基本的东西,但我正在试验 JavaFX,我很困惑为什么缩放 Canvas(使用 .setScaleX/Y)值为 2 不会导致 canvas 大两倍 width/height.
相关代码是这样的:(此时我没有使用任何 .fxml)
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
canvas.setScaleX(2);
canvas.setScaleY(2);
pane.getChildren().add(canvas);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
这导致 canvas 大约占 window 的 2/3(根据 width/heighth,而不是面积)。使用 3 的比例会使它填满整个 window(边缘有一个像素间隙),我不明白为什么。我查看了文档,但似乎缩放因子 2 应该导致尺寸的两倍。
编辑: 因此,根据下面的建议,将 canvas 翻译成 width/height 的一半可以解决问题。但是它在 StackPane 中居中也是如此,所以我不明白为什么 AnchorPane 在缩放后确实是 200x200 时不会通过它的 top/left 边缘来锚定它,就好像它是通过它的 100x100 边缘来锚定它一样.但是,如果 Canvas 是 100x100,那么如果只是在 StackPane 中居中,它是如何绘制到这些边界之外的呢?
编辑2: 通过一些试验,我认为我确认 AnchorPane 将 Canvas 定位为“好像”它仍然是 100x100。因此,通过将顶部和左侧锚点设置为 50,我可以获得与平移 50 或在 StackPane 中居中相同的结果。 但这意味着 Canvas 实际上是在其“边缘”之外“绘制”。这肯定不对吧?
您已经将 canvas 添加到窗格中,尝试在 pane.getChildren().add(canvas)
.
您在原始编辑中添加的信息 post 给出了问题的大部分答案。
首先请注意,scaleX
和 scaleY
围绕其中心缩放节点。来自 documentation:“定义坐标沿此节点的 X 轴围绕对象中心缩放的系数。”
其次,请注意,在该节点的布局计算中不会考虑应用于该节点的转换。来自 layout documentation(参见“视觉边界与布局边界”部分):
So for example ... if a
ScaleTransition
is used to pulse the size of a button, that pulse animation will not disturb layout around that button. If an application wishes to have the effect, clip, or transform factored into the layout of a node, it should wrap that node in aGroup
.
文档中引用的最后一句话是指 Group
的布局边界包括应用于组的子项(但不应用于组本身)的任何转换。
要可视化正在发生的事情,请从 100x100 canvas 开始。布局忽略了缩放,因此您可以将其可视化为在 应用缩放之前将 canvas 锚定到锚窗格的左上角 。然后 canvas 围绕其中心缩放,将所有四个角从两个维度的中心推开 50 像素。因此,锚窗格坐标系中 canvas 的边界是从 (-50, -50)
到 (150, 150)
。您可以通过添加
System.out.println(canvas.getBoundsInParent());
舞台演出后
有两种解决方法。一种是将 canvas 包裹在 Group
中。 Group
的布局边界将考虑 canvas:
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
canvas.setScaleX(2);
canvas.setScaleY(2);
Group group = new Group(canvas);
AnchorPane.setTopAnchor(group, 0.0);
AnchorPane.setLeftAnchor(group, 0.0);
pane.getChildren().add(group);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
另一种解决方案是应用缩放 canvas 左上角的变换:
public class Main extends Application {
@Override
public void start(Stage primaryStage){
AnchorPane pane = new AnchorPane();
Canvas canvas = new Canvas();
canvas.setWidth(100);
canvas.setHeight(100);
canvas.getGraphicsContext2D().setFill(Color.BLUE);
canvas.getGraphicsContext2D().fillRect(0,0,100,100);
Scale scale = new Scale(2,2);
scale.setPivotX(0);
scale.setPivotY(0);
canvas.getTransforms().add(scale);
pane.getChildren().add(canvas);
primaryStage.setScene(new Scene(pane, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}