Mastering JavaFX 10
上QQ阅读APP看书,第一时间看更新

Scene and SceneGraph

Every element of the JavaFX Scene is a part of the large graph (or a tree, strictly speaking) that starts from the root element of the Scene. All these elements are represented by the class Node and its subclasses.

All SceneGraph elements are split into two categories: Node and Parent. Parent is Node as well, but it can have children Node objects. Thus, Node objects are always leaves (endpoints of the SceneGraph), but Parent objects can be both leaves and vertices depending on whether they have children or not.

Parent objects generally have no idea what kind of Node objects their children are. They manage only direct children and delegate all further logic down the graph.

This way, you can build complex interfaces from smaller blocks step by step, organize UI elements in any way, and quickly change the configuration on the higher levels without modifying the lower ones.

Let's take a look at the next short JavaFX application, which shows a window with a checkbox and a gray background:

Take a look at the following code snippet:

public class HelloFX extends Application {
@Override
public void start(Stage stage) {
StackPane root = new StackPane();

CheckBox node = new CheckBox("I'm ready for FX!");
Rectangle rect = new Rectangle(70, 70, Color.GREEN);
root.getChildren().addAll(rect, node);

Scene scene = new Scene(root, 150, 100);
stage.setScene(scene);
stage.setTitle("Hello FX!");
stage.show();
}
}

From the code, the scenegraph here looks like this:

But, CheckBox itself consists of several nodes, and by digging deeper you can see that it looks like this:

You can always check the scenegraph structure by traversing the graph, starting from the Scene root. Here is a convenient method that prints the scenegraph and indents each parent:

 public void traverse(Node node, int level) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.println(node.getClass());
if (node instanceof Parent) {
Parent parent = (Parent) node;
parent.getChildrenUnmodifiable().forEach(n->traverse(n, level +1));
}
}

For our HelloFX example, it will provide the following output:

class javafx.scene.layout.StackPane
class javafx.scene.shape.Rectangle
class javafx.scene.control.CheckBox
class com.sun.javafx.scene.control.skin.LabeledText
class javafx.scene.layout.StackPane
class javafx.scene.layout.StackPane