image
CHAPTER
3
The Scene Graph
This chapter will provide a general overview of the scene graph and its functionality. The chapter will introduce the important public classes and their core functionalities, and it will show you how to create a scene graph and define a UI in it by using visual nodes such as buttons. In addition, you will learn how these elements can be laid out onscreen. Additionally, you’ll learn about interacting with the scene graph and different ways to define the layout of the scene graph.
Using and Integrating the Scene Graph in a JavaFX Application
In a JavaFX application, each stage has its own scene graph instance. Within this scene graph, you define a hierarchy of components, called nodes. All nodes that are part of a scene graph will be organized in a tree structure. For a more detailed look, let’s review the scene graph in the following JavaFX application:
image
image
This example shows a scene graph with several components displayed in the stage of an application, as shown in Figure 3-1. As you can see in the source code, you add different nodes within a defined hierarchy to the scene graph; all components added to the scene graph need to extend the class javafx.scene.Node. When using these nodes, you create a tree structure of components; for instance, nodes can hold other nodes that are children, as needed. A node that has children is a parent node. The javafx.scene.Parent class inherits from the Node class and allows you to manage the child nodes. The VBox and HBox classes used in the example inherit from the Parent class, and the hierarchy of the application is created by using these two classes and the Button control. As with the HBox and VBox classes, every control is a node. You may notice that, like the Component class in Swing, the inheritance hierarchy of the Node class is a bit more complicated. This will be described in more detail later in this chapter (see the “Node Types” section).
image
image
image
FIGURE 3-1.An application with a simple scene graph
The HBox and VBox classes manage the layout of child nodes by considering the preferred bounds of the child nodes. To display a component, you just need to add it to a visible scene graph. Each scene must have a root node, which is the main node of the scene graph and which contains all other nodes. Therefore, you need a Parent type. As you saw in the previous chapter’s example, you can add a scene graph to a stage. By showing the stage on the screen when launching the application, the scene graph and all its visible nodes will be rendered on the surface. Figure 3-2 outlines a simplified structure of a JavaFX application.
image
image
image
FIGURE 3-2.Structure of a JavaFX application
The Scene Class
So far, you’ve seen that the Scene class that defines the scene graph holds the root node and its children. The Scene class also provides a number of features and an inheritance hierarchy. Before looking at those topics, let’s first review the rest of the basic properties and functions of the Scene class. Table 3-1 provides an overview of the most important properties of the Scene class.
image
image
image
TABLE 3-1.Properties of the Scene Class
image
NOTE
You can access most properties either by using the JavaFX property API or (the POJO way) by using getter and setter methods. Table 3-1 and all following tables in this book will cover the JavaFX properties. Sometimes, only the properties that are specific to the current topic or that are used in common use cases will be shown in these tables. For additional information, refer to the JavaDoc or the JavaFX source code.
The following code extends the sample application and uses properties such as the cursor and fill properties of the Scene class. The code shows two different ways to set a property: by calling the appropriate setter method, which is setFill() in this case, and by retrieving the property object using the appropriate method. The method mySceneGraph.nodeOrientationProperty() is used in this case, and it returns the property instance of type ObjectProperty<NodeOrientation>. The value of the property can be set by calling setValue(…). When looking at the source code of the Scene class, you can see that the setter method does the same thing. These properties provide better styling and give the application its first functionalities.
image
image
This code uses various properties of the Scene class. A different background color and a mouse cursor are set for the scene graph, and the nodes’ orientation is changed. To see the background color of the scene graph, the background of the HBox and VBox is set to null since these nodes have their own background color by default and their layout is always maximized in the scene graph. Button 1 is now on the right side of the window instead of the left side, and so on.
In addition, the hierarchy of the nodes in the sample application has changed. The VBox is no longer part of the hierarchy and is therefore not displayed. However, two of the EventHandler properties have been set. The event handlers that are defined here will always execute when a key or a mouse button is pressed in the scene graph; when that happens, the root node of the scene graph will change. You can see this behavior in action by clicking the black background of the demo application. Now Button 4 and Button 5 should appear. By pressing any key on the keyboard, the HBox with the corresponding button will appear again.
image
NOTE
Lambda expressions are used to define the EventHandler properties in the source code of the demo application. Lambdas are a new language feature introduced in version 8 of Java, so some developers may not have used them yet. JavaFX is well designed for the use of lambda expressions, which are simply source code. For this reason, I use them in this book as often as possible. In theory, all examples shown in the book can be refactored to a version that doesn’t use lambda expressions. However, refactoring the previous example makes the two lines of code increase to 12 lines (as shown in the following listing) by using internal classes.
image
Additionally, this structure creates code that is more complicated to read.
In addition to the properties described earlier, there are some useful methods defined in the Scene class, as described in Table 3-2.
image
TABLE 3-2.Methods of the Scene Class
The following example uses the event filter and snapshot features:
image
image
This code adds an event filter for all mouse click events to the scene graph. As mentioned in the previous table, the defined event handler will be called before the events can be passed to the normal life cycle of the event dispatcher. The event handler will be called even if a button was clicked in the scene graph, for example. All click events will be handled directly and passed only to child components. In the application, you can simply click any point in the application window. Even if you click an empty area of the scene graph or the button, the background of the scene graph will change its color.
The second method of the scene graph that is used here is the snapshot(…) method to create a screenshot of the current scene graph. In the example, this method is called inside the saveSnapshotOnDisc(…) method. The snapshot is created and saved as a PNG file on the hard drive. By pressing any key, the KeyEventHandler creates the snapshot.
Event Handling
JavaFX knows several types of input events on which an application can react to user input. Event handlers for these event types can be used in the scene graph to create an interaction between the user and the application. All supported input events are defined in JavaFX as a derivation of the class javafx.scene.input.InputEvent. JavaFX can deal with considerably more input types than Swing. Additionally, all modern input types such as gestures and touch input are supported. By using these features, developers can define a better user experience than with any other Java UI framework. Figure 3-3 contains an overview of the supported event types and their inheritance.
image
image
image
FIGURE 3-3.Class hierarchy of JavaFX events
In addition to the classic mouse and key events that already exist in AWT or Swing, touch and gesture events have been added to JavaFX, so you can use JavaFX on a multitouch environment such as a tablet and have your application respond to finger input by the user. For example, a pinch, shown in Figure 3-4, will be passed directly as a zoom event to the JavaFX scene graph.
image
image
image
FIGURE 3-4.Pinch events
image
NOTE
All modern MacBooks embed a multitouchpad that can interpret gestures. Most of them are supported in the Mac OS, and if a JavaFX program is running on such a system, the gesture events will be passed to the program. If you don’t have a tablet but own a MacBook, you can easily test the gesture events by using the touchpad of your device.
Many examples in this book will use input events to create some interaction, so there is no special example that contains all the different event types. The following code snippet shows how an EventHandler can be set to react after a special button is clicked:
image
image
Each event that occurs on the scene graph will be handled by the event dispatcher of the scene graph. An event dispatch sends all received events to the registered event handlers and filters. Whenever an event occurs, four steps will take place:
1. Target selection
2. Route construction
3. Event capturing
4. Event bubbling
First, the target of the event will be determined. This step depends on the event type. If a mouse click occurs, the event target will be the topmost node at the position of the mouse cursor that has not set the mouseTransparent property to true. The target of a key event is the currently focused node. Touch and gesture events have some special rules for how the target node will be selected too. After the target node is defined, a route through the scene graph will be defined. This route contains all nodes between the root node of the scene graph and the target node. This route is called the event dispatch chain. In the event-capturing phase, the event will be passed through the chain. This dispatch starts with the scene graph instance and goes down the complete route to the target node. If any of these nodes has registered an event filter for the given event type, the event handler that is defined as the filter will be called. Each event has a consumed flag. Whenever any event handler consumes an event by setting this flag, the processing of the event will stop. If no registered filter consumes the event, the target node will be reached. At this moment, the last phase will start. In the event-bubbling phase, the event will return along the dispatch chain from the target to the root node of the scene graph. Here, each event handler that is registered for the given event type will be called. As long as no handler consumes the event, it will return to the next node up the chain until the root node is reached, and the event dispatching will stop.
Node Types
As mentioned earlier, any component that can be added to a scene graph has to extend the Node class. The inheritance of the Node class is a little more complicated than you might know from other cases such as Swing, for example. Figure 3-5 shows a diagram with the most important parts of the class hierarchy.
image
image
image
FIGURE 3-5.Node class hierarchy
The diagram may be overwhelming at first, but all the classes in the diagram can split into three different main types: primitive nodes, LayoutPanes, and complex nodes such as controls.
Primitive Nodes
Among the primitive nodes are different shape types such as circles, rectangles, and lines. There are, thanks to the 3D support of JavaFX, still primitive three-dimensional shapes like a box. All these nodes can be easily added to a scene graph. In the following example code, a rectangle is added to the scene graph:
image
image
As you can see, the shapes in the code are treated exactly as other nodes, in other words, like controls. The use of these elements is not different from other examples such as buttons in the scene graph. All the other elements that extend the Node class can be added in this way in the scene graph.
Using the scene graph even with primitives such as lines is one of the advantages of JavaFX over other UI toolkits like Swing. All visual elements are real nodes in the scene graph, and internally more complex components like buttons are composed by using a set of primitive shapes.
As you can see in Figure 3-6, a RadioButton control is internally composed from different nodes. To display the text information on the radio button, a LabeledText object is used. This is a derivative of the javafx.scene.shape.Text class and mainly used in the skin of controls. The selection circle of the radio button is created by two nested StackPanes. These StackPanes are styled by CSS to get the specific look shown here. The individual nodes will be styled and laid out by the radio button skin. This special functionality will be explained in Chapters 9 and 10. In Swing, an inner canvas is used in which pixel graphics are painted to define the visual representation of a component. You won’t find this technology in JavaFX nodes.
image
image
image
FIGURE 3-6.Composition of a RadioButton
image
NOTE
JavaFX contains a special node type called Canvas. This node provides paint functionality like you may know from Swing and Java2D, but the Canvas class is never used internally in JavaFX nodes. Here, CSS and other node types such as shapes are always used. The Canvas class will be described in Chapter 7.
LayoutPanes
The LayoutPanes category of nodes contains all panes. These classes are responsible for the layouts and therefore the positioning of child components. I’ll briefly describe the class hierarchy of the panes: Each node that needs to encapsulate a set of child nodes needs to extend the javafx.scene.Parent class. This class provides only the ability to wrap any type of node. As a next step, the javafx.scene.layout.Region class defines the Region type that is a resizable Parent class that can be styled using CSS. The Parent and Region classes can both contain a set of children. The children of a parent are defined as an ObservableList<Node>. Neither the Parent nor Region class provide public methods to change its children. The javafx.scene.layout.Pane class adds this feature. While the Parent class defines the getChildrenUnmodifiable() method that returns a read-only list of all children, the Pane class defines a getChildren() method that returns a modifiable list of children. Therefore, all default layout containers in JavaFX, such as HBox or VBox, extend the Pane class, and developers can add child nodes to them by calling pane.getChildren().add(myButton), for example. All controls such as Button controls inherit from the Region class because they need to hold and lay out some primitive shapes that are needed to visualize the button. But developers can never easily add new nodes to a button. By using the descried class hierarchy, it will be more difficult for developers to use some of the node types in a wrong way.
All the nodes that implement different layouts to align its children extend the Pane class. Instances of these classes should be used when all the controls inside a scene graph need to be laid out. In the previous examples, you already saw two pane types: HBox and VBox. Table 3-3 describes the various layout panes.
image
TABLE 3-3.Overview of Pane Classes
Some panes, such as the HBox or FlowPane, can be easily used in code. Others, such as the AnchorPane, are flexible, and therefore they need more configuration in code to create a special layout. As a best practice, you should create these layouts in Scene Builder. When using Scene Builder, you create an FXML file that describes the layout. (FXML will be discussed in the “FXML” section, and an example with a complex layout that is created in Scene Builder will be shown.) To achieve the desired layout structure, you can nest different containers within a JavaFX application. The first demo application in this chapter wrapped a VBox inside an HBox to create a special screen layout, for example. As you will see later, it is easy to create your own LayoutPanes, too, but doing so requires knowledge about the internal layout mechanism of JavaFX.
Complex Nodes
All other classes that extend the Node class are components that fall into the complex node category. The largest part of this group includes the controls such as buttons, labels, and tables. These all extend the Control class. Controls have a lot of features; you can simply change their style and behavior or add a tooltip, for example. I will discuss the different features of controls in more depth in the following chapters. In addition to them, there are some other special nodes such as WebView, Canvas, and Chart. Table 3-4 describes these components.
image
TABLE 3-4.Special Components in JavaFX
Node Basics
As mentioned, all components that can be added to a scene graph extend the Node class. This class offers a set of properties and methods. Table 3-5 contains an overview of the class properties that can be useful while working with the scene graph.
image
image
image
image
image
TABLE 3-5.Properties of the Node Class
image
image
image
FIGURE 3-7.Examples for the blendMode property
In addition to these properties, the Node class provides some helpful methods that can be used to manage some basic tasks when working with nodes. Some of these methods are related to the ones that are part of the Scene class. All the different methods of the Node class won’t be shown here. For a complete overview, please refer to the JavaDoc or the source of the Node class.
You can use the properties and methods in code to specify the characteristics of the used nodes. As an example, the following application uses several of the mentioned properties to offer some special functionality:
image
image
When running the application shown in Figure 3-8, a button and a check box will be part of the scene graph. Compared to the previous applications, this one is a bit different. The check box that is used has a reflection effect. Additionally, it is not completely opaque. The exclamation point of the button text is on the left side. This is the result of the different node orientation that is set on the node. In addition, both controls have a unique ID. By clicking the button, the changeNodeVisibility(…) method is called. This method uses the lookup(…) method to find the node with the given ID inside the scene graph. Because the lookup(…) method uses CSS ID specification, a hash tag must be added as a prefix to the ID. (You can read more about the specification at www.w3.org/TR/CSS21/syndata.html#value-def-identifier.) Clicking the button changes the visibility of the check box.
image
image
image
FIGURE 3-8.The example application
image
NOTE
This example application has some new features that weren’t mentioned until now. By calling the setOnAction(…) method on the Button instance, a special event handler is set on the button. This handler will be called whenever the button is clicked or, rather, used. This can be triggered by different input events, such as a mouse click, a pressed key, or a touch event, for example. Most of the controls that are provided by JavaFX support event handlers for common use cases. A ComboBox supports event handler instances to react to the behavior of the selection pop-up, for example.
FXML
In this chapter, most of the example applications create a scene graph with some controls. In all the examples, the layout of the application is simple and couldn’t be used in a business application. In professional applications, you usually have complex layouts that need to interleave different panes and would use, for example, the AnchorPane, which is considerably more complex than the BorderPane or FlowPane. In the following code block, an AnchorPane is used to lay out two buttons. The AnchorPane class offers some static methods to affect the layout behavior of child components in an AnchorPane. Figure 3-9 shows the application view.
image
image
image
FIGURE 3-9.The example application
image
image
As you can see in the code, you need to add a number of lines to define a specific layout. The more controls and panes you need in your application, the more complex the code becomes. In Swing, this was a common problem too. By using WYSIWYG editors, developers often created source code that defined the layout of Swing applications, but this produced additional problems, including that the source code couldn’t be edited by hand or the editor couldn’t parse special source code.
To combat these problems, JavaFX provides FXML. As mentioned in earlier chapters, FXML is an XML-based language that can be used to provide the structure of user interfaces. You use it to define the UI layout separate from the application logic of your code. It is highly recommended that you use FXML as often as possible. Using FXML and then using Scene Builder as a WYSIWYG editor is a best practice when developing views for a JavaFX application. Even when you want to create some modern and skinned views, you can use these tools. The following code shows the FXML that defines an AnchorPane with the layout that was developed in Java source earlier:
image
image
I won’t discuss the definition and structure of FXML in depth, but you can see in this example that you can define the layout parameters directly in FXML. Additionally, you can define properties such as the text of buttons in FXML.
Once you create an FXML file, you need to load the file at runtime. This can be easily done by using the FXMLLoader class:
image
image
In the code, note that getClass().getResource(…) is used to load the FXML file. This is a best practice to load resources in Java. To do this, you need to place the layout.fxml file in the same package as the class file, SceneGraphApp.class in this case. Incidentally, most modern Java applications use a setup that was defined by Maven some years ago where all Java code is placed in an src/main/java subfolder. It is recommend that you use this structure and don’t put any resource files such as images, XML, or CSS files in this folder. For those resources, create an src/main/resources folder. The getResource(…) method will still work if the resource is located in the same package as the class but in a resources folder. Here is a working folder tree for the given example:
image
image
Once this structure is created, most modern IDEs will identity the setup and add src/main/java and src/main/resources automatically to the classpath. Sometimes, you need to set up your environment by hand and add these folders to the classpath.
In addition to these features, FXML provides a way to interact with the UI and bind a controller to the view. When defining an FXML file, you can define a controller class. The following snippet shows how a controller can be specified in FXML:
image
image
In addition to the controller class that was added as a parameter to the AnchorPane, new parameters are defined for the buttons in the FXML. The fx:id parameters define unique IDs for the two buttons. By using these IDs, the buttons can be accessed in the controller class. This can be done by using special annotations. Event handlers can be defined in FXML too. In the definition of the save button, for example, an additional parameter is added. This onAction parameter links to a method that is part of the controller. When the button is clicked, the save method will be triggered. Furthermore, each controller class can define an initialize() method. This method will be called when the controller is created and all annotated values are injected. The following code shows how a controller that matches the FXML file may look:
image
image
When the FXML file is loaded, a new instance of the controller class will be created automatically, and all fields that have the @FXML annotation will be filled by injection. Additionally, the save(…) method will be bound to the onAction event of the save button.
Summary
This chapter showed all the basic functionality of the scene graph. It covered the different types of nodes and the basic usage of event handling, and it introduced FXML. Some of the basic features of JavaFX were only briefly mentioned. For further information on the basics of JavaFX, review a beginner’s guide to learning JavaFX, such as Quick Start Guide to JavaFX (McGraw-Hill, 2014).
After reading the chapter, you should now understand all the basic technologies and methods for creating a simple JavaFX application with a default layout. The next chapters will define special features such as the internal layout mechanism of JavaFX, which will help you create special layout panes for applications.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.93.222