简体   繁体   English

如何居中JavaFX场景图“相机”

[英]How to center javafx scene graph “camera”

I have a group with two circles on it, when I move one of them with a translate transition I should see the stationary one remain at the center(which is in the middle of the scene graph) and the other one move. 我有一个带有两个圆的组,当我用平移过渡移动其中一个时,我应该看到静止的一个保持在中心(位于场景图的中间),而另一个移动。 Instead what happens is the "camera" follows the moving circle making it seem like they are both moving apart. 取而代之的是,“摄像机”跟随移动的圆圈,看起来好像它们都在分开。

Is there a way to center the camera on 0,0 so that it remains there instead of following the circle? 有没有一种方法可以将相机定在0,0的中心,以便它保持在那里而不是跟随圆圈呢?

 import javafx.animation.Interpolator;
 import javafx.animation.TranslateTransition;
 import javafx.application.Application;
 import javafx.scene.Group;
 import javafx.scene.Scene;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.paint.Color;
 import javafx.scene.shape.Circle;
 import javafx.stage.Stage;
 import javafx.util.Duration;

 public class Test extends Application
{
public static void main(String[] args)
{
    launch(args);
}

public void start(Stage stage)
{
    BorderPane root = new BorderPane();
    root.setStyle("-fx-background-color: Black");
        Group graph = new Group();
        root.setCenter(graph);
        graph.setLayoutX(250);
        graph.setLayoutY(250);

        Circle circle = new Circle(0,0,5);
        circle.setFill(Color.ORANGE);
        graph.getChildren().add(circle);

        Circle circle2 = new Circle(0, 0, 5);
        circle2.setFill(Color.AQUA);
        graph.getChildren().add(circle2);

    TranslateTransition t = new TranslateTransition(Duration.millis(1000), circle);
    t.setFromX(0);
    t.setToX(100);
    t.setFromY(0);
    t.setToY(0);

    t.setInterpolator(Interpolator.LINEAR);
    t.play();

    stage.setTitle("Circle Test");
    stage.setScene((new Scene(root, 500, 500)));
    stage.show();
}
 }

To understand what is happening with the layout here, first note that the layout coordinates of the Group graph are ignored entirely, because you place graph in a layout container (a BorderPane ). 要了解什么是这里的布局,首先要注意的是,布局坐标发生Group graph被完全忽略,因为你把graph在布局容器( BorderPane )。 (Comment out the setLayoutX and setLayoutY lines and you will see they make no difference.) The layout container will size its child nodes according to 1. how much space it has for them, 2. the child nodes' min, preferred, and max sizes. (注释掉setLayoutXsetLayoutY行,您将发现它们没有区别。)布局容器将根据1.为其子节点保留多少空间,2.根据子节点的最小,首选和最大大小来调整其子节点的大小。大小。 Since the BorderPane doesn't have any other child nodes in this example, it wants to allocate all its available space to the graph . 由于BorderPane在此示例中没有任何其他子节点,因此它希望将其所有可用空间分配给graph Since graph is in the center, if there is space it cannot allocate to it, it will center it, leaving the rest of the space unused. 由于graph位于中心,因此如果没有空间可以分配,则它将居中,剩下的空间则不使用。

Group s behave differently to Region s (which include Control s, Pane s, and their subclasses): according to the documentation they are not resizable and take on the collective bounds of their children . Group的行为与Region (包含ControlPane及其子类)的Region不同:根据文档,它们的大小不可调整,具有其子代的集体边界

At the beginning of your animation, both circles are coincident, centered at (0,0) and with radius 5 : so their bounding boxes (and consequently the bounding box of the Group ) has top left corner at (-5,-5) and width and height of 10 . 在动画开始时,两个圆是重合的,以(0,0)为中心,半径为5 :因此,它们的边界框(因此是Group的边界框)的左上角为(-5,-5)宽度和高度为10 This square 10x10 bounding box cannot be made bigger (since it's a Group , which is not resizable), and is centered on the screen. 不能将这个10x10方形边框做大(因为它是Group ,无法调整大小),并且位于屏幕中央。 Since the BorderPane has 500 pixels of total width available, there are 490 pixels of unused width, which are divided equally on either side of the Group to center it: 245 to the left and 245 to the right. 由于BorderPane具有500可用像素总宽度的,有490个像素的未使用的宽度,这些都对的任一侧相等地划分Group使其居中: 245的左侧和245到右边。 So the left edge of the Group , which is the left edge of both the circles, is at x=245 in the BorderPane coordinate system. 因此, Group的左边缘(即两个圆的左边缘)在BorderPane坐标系中的x=245

At the end of the animation, one circle remains at (-5,-5) with width 10x10 , while the other has been translated 100 pixels to the right, so its bounding box extends from (95, -5) to (105, 5) . 在动画结束时,一个圆圈保留在(-5,-5) ,宽度为10x10 ,而另一个圆圈已向右平移100像素,因此其边界框从(95, -5)扩展到(105, 5) Consequently, the bounding box of the Group , which takes on the collective bounds of its child nodes, has top left at (-5, -5) , width 110 and height 10 . 因此, Group的边界框采用其子节点的集体边界,在(-5, -5) ,宽度110和高度10处位于左上方。 This box cannot be resized, so the BorderPane 's layout mechanism centers this box in the area it has available. 此框无法调整大小,因此BorderPane的布局机制将其置于可用区域的中心。 Since the BorderPane has a width of 500 pixels available, there are 390 unused pixels in width which are divided equally on either side: 195 on the left of the Group and 195 on the right. 由于BorderPane具有的宽度500可用的像素中,有在宽度390个未使用的像素被在任一侧相等地划分: 195上的左侧Group195上的右侧。 So at this point, the left edge of the Group , which is the left edge of the untranslated circle, is at x=195 in the BorderPane coordinate system. 因此,此时, Group的左边缘(即未平移圆的左边缘)在BorderPane坐标系中位于x=195 Consequently, at the end of the animation, the untranslated circle has moved 50 pixels (half of the translation distance) to the left in the BorderPane 's coordinate system. 因此,在动画结束时,未平移的圆圈在BorderPane的坐标系中向左移动了50像素(平移距离的一半)。

A more natural thing to do here is to use a Pane instead of a Group . 在这里做的更自然的事情是使用Pane而不是Group A Pane is resizable, so the BorderPane will simply expand it to fill all the available space. Pane是可调整大小的,因此BorderPane会简单地将其展开以填充所有可用空间。 Thus it will sit in the top left of the BorderPane and fill the BorderPane . 因此它将位于BorderPane左上方,并填充BorderPane The bounds of the Pane start at (0,0) and extend to its width and height. Pane的边界从(0,0)开始,并扩展到其宽度和高度。 Thus if you simply change Group to Pane , the untranslated circle will not move during the animation, as you want. 因此,如果仅将“ Group更改为“ Pane ,则未平移的圆不会在动画过程中根据需要移动。

However, the circles will now both start in the top left of the pane instead of the center. 但是,圆圈​​现在都将从窗格的左上角而不是中心开始。 If you want them to start in the center, you can change the coordinates of the circles themselves, so they start centered at (250, 250) : 如果希望它们从中心开始,则可以更改圆自身的坐标,因此它们以(250, 250)为中心开始:

import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Test extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage stage) {
        BorderPane root = new BorderPane();
        root.setStyle("-fx-background-color: Black");
        Pane graph = new Pane();
        root.setCenter(graph);
        // graph.setLayoutX(250);
        // graph.setLayoutY(250);

        Circle circle = new Circle(250, 250, 5);
        circle.setFill(Color.ORANGE);
        graph.getChildren().add(circle);

        Circle circle2 = new Circle(250, 250, 5);
        circle2.setFill(Color.AQUA);
        graph.getChildren().add(circle2);

        TranslateTransition t = new TranslateTransition(Duration.millis(1000), circle);
        t.setFromX(0);
        t.setToX(100);
        t.setFromY(0);
        t.setToY(0);

        t.setInterpolator(Interpolator.LINEAR);
        t.play();

        stage.setTitle("Circle Test");
        stage.setScene((new Scene(root, 500, 500)));
        stage.show();
    }
}

As an alternative, you could use a Pane as the root, instead of a BorderPane . 或者,您可以使用Pane作为根,而不是BorderPane A plain Pane doesn't do any layout, so in this case the layoutX and layoutY settings will take effect. 普通Pane不执行任何布局,因此在这种情况下, layoutXlayoutY设置将生效。 Thus you can revert the centers of the circles to (0,0) , and use the layout settings on graph to center it: 因此,您可以将圆心还原为(0,0) ,并使用graph上的布局设置将其居中:

import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Test extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage stage) {
        Pane root = new Pane();
        root.setStyle("-fx-background-color: Black");
        Pane graph = new Pane();
        root.getChildren().add(graph);
         graph.setLayoutX(250);
         graph.setLayoutY(250);

        Circle circle = new Circle(0, 0, 5);
        circle.setFill(Color.ORANGE);
        graph.getChildren().add(circle);

        Circle circle2 = new Circle(0, 0, 5);
        circle2.setFill(Color.AQUA);
        graph.getChildren().add(circle2);

        TranslateTransition t = new TranslateTransition(Duration.millis(1000), circle);
        t.setFromX(0);
        t.setToX(100);
        t.setFromY(0);
        t.setToY(0);

        t.setInterpolator(Interpolator.LINEAR);
        t.play();

        stage.setTitle("Circle Test");
        stage.setScene((new Scene(root, 500, 500)));
        stage.show();
    }
}

You can change the class name to whatever you want. 您可以将类名更改为所需的任何名称。

The problem you had was that you added it through the setCenter() method which automatically makes its center the center of the pane. 您遇到的问题是您通过setCenter()方法添加了它,该方法自动使它的中心成为窗格的中心。

I hope this came in time. 我希望这是及时的。

import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class NewClass extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage stage) {
        BorderPane root = new BorderPane();
        root.setStyle("-fx-background-color: #efefef");
        Group graph = new Group();
        root.getChildren().add(graph);
        graph.setLayoutX(250);
        graph.setLayoutY(250);

        Circle circle = new Circle(0, 0, 5);
        circle.setFill(Color.ORANGE);
        graph.getChildren().add(circle);

        Circle circle2 = new Circle(0, 0, 5);
        circle2.setFill(Color.AQUA);
        graph.getChildren().add(circle2);

        TranslateTransition t = new TranslateTransition(Duration.millis(1000), circle);
        t.setFromX(0);
        t.setToX(100);
        t.setFromY(0);
        t.setToY(0);

        t.setInterpolator(Interpolator.LINEAR);
        t.setCycleCount(5);
        t.play();

        stage.setTitle("Circle Test");
        stage.setScene((new Scene(root, 500, 500)));
        stage.show();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM