Baixe Capítulo 31 - JavaFX y FXML Avanzado - Liang-Java-Comp11e e outras Resumos em PDF para Informática, somente na Docsity!
Objectives
■ ■ To specify styles for UI nodes using JavaFX CSS (§31.2).
■ ■ To create quadratic curve, cubic curve, and path using the QuadCurve ,
CubicCurve , and Path classes (§31.3).
■ ■ To translate, rotate, and scale to perform coordinate transformations
for nodes (§31.4).
■ ■ To define a shape’s border using various types of strokes (§31.5).
■ ■ To create menus using the Menu , MenuItem , CheckMenuItem , and
RadioMemuItem classes (§31.6).
■ ■ To create context menus using the ContextMenu class (§31.7).
■ ■ To use SplitPane to create adjustable horizontal and vertical panes
■ ■ To create tab panes using the TabPane control (§31.9).
■ ■ To create and display tables using the TableView and TableColumn
classes (§31.10).
■ ■ To create JavaFX user interfaces using FMXL and the visual Scene
Builder (§31.11).
Advanced JavaFX
and FXML
CHAPTER
31-2 Chapter 31 Advanced JavaFX and FXML
31.1 Introduction
JavaFX can be used to develop comprehensive rich Internet applications.
Chapters 14–16 introduced basics of JavaFX, event-driven programming, animations, and
simple UI controls. This chapter introduces some advanced features for developing compre-
hensive GUI applications.
31.2 JavaFX CSS
JavaFX cascading style sheets can be used to specify styles for UI nodes.
JavaFX cascading style sheets are based on CSS with some extensions. CSS defines the style
for webpages. It separates the contents of webpages from its style. JavaFX CSS can be used to
define the style for the UI and separates the contents of the UI from the style. You can define
the look and feel of the UI in a JavaFX CSS file and use the style sheet to set the color, font,
margin, and border of the UI components. A JavaFX CSS file makes it easy to modify the style
without modifying the Java source code.
A JavaFX style property is defined with a prefix –fx- to distinquish it from a property in
CSS. All the available JavaFX properties are defined in http://docs.oracle.com/javafx/2/api/
javafx/scene/doc-files/cssref.html. Listing 31.1 gives an example of a style sheet.
Listing 31.1 mystyle.css
.plaincircle { -fx-fill: white; -fx-stroke: black; } .circleborder { -fx-stroke-width: 5; -fx-stroke-dash-array: 12 2 4 2; } .border { -fx-border-color: black; -fx-border-width: 5; } #redcircle { -fx-fill: red; -fx-stroke: red; } #greencircle { -fx-fill: green; -fx-stroke: green; }
A style sheet uses the style class or style id to define styles. Multiple style classes can
be applied to a single node, and a style id to a unique node. The syntax .styleclass
defines a style class. Here, the style classes are named plaincircle , circleborder , and
circleborder. The syntax #styleid defines a style id. Here, the style ids are named red-
circle and greencircle.
Each node in JavaFX has a styleClass variable of the List type, which
can be obtained from invoking getStyleClass(). You can add multiple style classes to
a node and only one id to a node. Each node in JavaFX has an id variable of the String
type, which can be set using the setID(String id) method. You can set only one id
to a node.
The Scene and Parent classes have the stylesheets property, which can be
obtained from invoking the getStylesheets() method. This property is of the
Point
Key
Point
Key
31-4 Chapter 31 Advanced JavaFX and FXML
The program loads the style sheet from the file mystyle.css by adding it to the
stylesheets property (line 13). The file should be placed in the same directory with
the source code for it to run correctly. After the style sheet is loaded, the program sets the
style class plaincircle for circle1 and circle2 (lines 22 and 23) and sets the style
id redcircle for circle3 (line 24). The program sets style classes circleborder and
plaincircle and an id greencircle for circle4 (lines 28 and 29). The style class
border is set for both pane1 and pane2 (lines 20 and 31).
The style sheet is set in the scene (line 13). All the nodes inside the scene can use this
style sheet. What would happen if line 13 is deleted and the following line is inserted
after line 15?
pane1.getStylesheets().add("mystyle.css");
In this case, only pane1 and the nodes inside pane1 can access the style sheet, but pane
and circle4 cannot use this style sheet. Therefore, everything in pane1 is displayed the same
as before the change, and pane2 and circle4 are displayed without applying the style class
and id, as shown in Figure 31.1b.
Note the style class plaincircle and id greencircle both are applied to circle
(lines 28 and 29). plaincircle sets fill to white and greencircle sets fill to green. The
property settings in id take precedence over the ones in classes. Thus, circle4 is displayed
in green in this program.
31.2.1 How do you load a style sheet to a Scene or a Parent? Can you load multiple style
sheets?
31.2.2 If a style sheet is loaded from a node, can the pane and all its containing nodes access
the style sheet?
31.2.3 Can a node add multiple style classes? Can a node set multiple style ids? 31.2.4 If the same property is defined in both a style class and a style id and applied to a
node, which one has the precedence?
31.3 QuadCurve , CubicCurve , and Path
JavaFX provides the QuadCurve , CubicCurve , and Path classes for creating advanced
shapes.
Section 14.11 introduced drawing simple shapes using the Line , Rectangle , Circle ,
Ellipse , Arc , Polygon , and Polyline classes. This section introduces drawing advanced
shapes using the CubicCurve , QuadCurve , and Path classes.
31.3.1 QuadCurve and CubicCurve
JavaFX provides the QuadCurve and CubicCurve classes for modeling quadratic curves and
cubic curves. A quadratic curve is mathematically defined as a quadratic polynomial. To create
a QuadCurve , use its no-arg constructor or the following constructor:
QuadCurve( double startX, double startY, double controlX, double controlY, double endX, double endY)
where ( startX , startY ) and ( endX , endY ) specify two endpoints and ( controlX , controlY )
is a control point. The control point is usually not on the curve instead of defining the trend of
the curve, as shown in Figure 31.2a. Figure 31.3 shows the UML diagram for the QuadCurve
class.
Point
Check
Point
Key
31.3 QuadCurve, CubicCurve, and Path 31-
A cubic curve is mathematically defined as a cubic polynomial. To create a CubicCurve ,
use its no-arg constructor or the following constructor:
CubicCurve( double startX, double startY, double controlX1, double controlY1, double controlX2, double controlY2, double endX, double endY)
where ( startX , startY ) and ( endX , endY ) specify two endpoints and ( controlX1 ,
controlY1 ) and ( controlX2 , controlY2 ) are two control points. The control points are
usually not on the curve, instead define the trend of the curve, as shown in Figure 31.2b.
Figure 31.4 shows the UML diagram for the CubicCurve class.
F igure 31.2 (a) A quadratic curve is specified using three points. (b) A cubic curve is
specified using four points.
(controlX, controlY)
(startX, startY) (endX, endY)
(controlX1, controlY1)
(startX, startY) (endX, endY)
(controlX2, controlY2)
(a) (b)
Figure 31.3 QuadCurve defines a quadratic curve.
The getter and setter methods for property values and a getter for prop- javafx.scene.shape.QuadCurve erty itself are provided in the class, but omitted in the UML diagram for brevity.
-startX: DoubleProperty -startY: DoubleProperty -endX: DoubleProperty -endY: DoubleProperty -controlX: DoubleProperty -controlY: DoubleProperty
The x-coordinate of the start point (default 0). The y-coordinate of the start point (default 0). The x-coordinate of the end point (default 0). The y-coordinate of the end point (default 0). The x-coordinate of the control point (default 0). The y-coordinate of the control point (default 0). Creates an empty quad curve. Creates a quad curve with the specified arguments.
+QuadCurve() +QuadCurve(startX: double, startY: double, controlX: double, controlY: double, endX: double, endY: double)
The getter and setter methods for property values and a getter for property javafx.scene.shape.CubicCurve itself are provided in the class, but omitted in the UML diagram for brevity.
-startX: DoubleProperty -startY: DoubleProperty -endX: DoubleProperty -endY: DoubleProperty -controlX1: DoubleProperty -controlY1: DoubleProperty -controlX2: DoubleProperty -controlY2: DoubleProperty
The x-coordinate of the start point (default 0). The y-coordinate of the start point (default 0). The x-coordinate of the end point (default 0). The y-coordinate of the end point (default 0). The x-coordinate of the first control point (default 0). The y-coordinate of the first control point (default 0). The x-coordinate of the second control point (default 0). The y-coordinate of the second control point (default 0). Creates an empty cubic curve. Creates a cubic curve with the specified arguments.
+CubicCurve() +CubicCurve(startX: double, startY: double, controlX1: double, controlY1: double, controlX2: double, controlY2: double, endX: double, endY: double)
Figure 31.4 CubicCurve defines a quadratic curve.
31.3 QuadCurve, CubicCurve, and Path 31-
The program creates a CubicCurve with the specified start, first control, second control,
and end points (lines 24 and 25) and places the CubicCurve to the pane (line 29). To illustrate
the control points, the program also displays the control points in the pane (lines 29–32).
Note the curves are filled with color. The program sets the color to white and stroke to black
in order to display the curves (lines 17 and 18, 26 and 27). If these code lines are removed from
the program, the sample run would look like the one in Figure 31.5b.
31.3.2 Path
The Path class models an arbitrary geometric path. A path is constructed by adding path
elements into the path. The PathElement is the root class for the path elements MoveTo ,
HLineTo , VLineTo , LineTo , ArcTo , QuadCurveTo , CubicCurveTo , and ClosePath.
You can create a Path using its no-arg constructor. The process of the path construction can
be viewed as drawing with a pen. The path does not have a default initial position. You need to set
an initial position by adding a MoveTo(startX, startY) path element to the path. Adding a
HLineTo(newX) element draws a horizontal line from the current position to the new x -coordinate.
Adding a VLineTo(newY) element draws a vertical line from the current position to the new
y -coordinate. Adding a LineTo(newX, newY) element draws a line from the current position to
the new position. Adding an ArcTo(radiusX, radiusY, xAxisRotation, newX, newY,
largeArcFlag, sweepArcFlag) element draws an arc from the previous position to the new
position with the specified radius. Adding a QuadCurveTo(controlX, controlY, newX,
newY) element draws a quadratic curve from the previous position to the new position with the
specified control point. Adding a CubicCurveTo(controlX1, controlY1, controlX2,
controlY2, newX, newY) element draws a cubic curve from the previous position to the new
position with the specified control points. Adding a ClosePath() element closes the path by
drawing a line that connects the starting point with the end point of the path.
Listing 31.4 gives an example that creates a path. A sample run of the program is shown
in Figure 31.6.
Listing 31.4 PathDemo.java
1 import javafx.application.Application; 2 import javafx.scene.Scene; 3 import javafx.scene.layout.Pane; 4 import javafx.scene.paint.Color; 5 import javafx.scene.shape.*; 6 import javafx.stage.Stage; 7 8 public class PathDemo extends Application { 9 @Override // Override the start method in the Application class 10 public void start(Stage primaryStage) { 11 Pane pane = new Pane(); 12 13 // Create a Path 14 Path path = new Path(); 15 path.getElements().add( new MoveTo( 50.0 , 50.0 )); 16 path.getElements().add( new HLineTo( 150.5 )); 17 path.getElements().add( new VLineTo( 100.5 )); 18 path.getElements().add( new LineTo( 200.5 , 150.5 )); 19 20 ArcTo arcTo = new ArcTo( 45 , 45 , 250 , 100.5 , 21 false , true ); 22 path.getElements().add(arcTo); 23 24 path.getElements().add( new QuadCurveTo( 50 , 50 , 350 , 100 )); 25 path.getElements().add( 26 new CubicCurveTo( 250 , 100 , 350 , 250 , 450 , 10 ));
31-8 Chapter 31 Advanced JavaFX and FXML
28 path.getElements().add( new ClosePath()); 29 30 pane.getChildren().add(path); 31 path.setFill( null ); 32 Scene scene = new Scene(pane, 300 , 250 ); 33 primaryStage.setTitle( "PathDemo" ); // Set the window title 34 primaryStage.setScene(scene); // Place the scene in the window 35 primaryStage.show(); // Display the window 36 } 37 }
Figure 31.6 You can draw a path by adding path elements.
HLineTo VLineTo
LineTo ArcTo QuadCurveTo CubicCurveTo
ClosePath
The program creates a Path (line 14), moves its position (line 15), and adds a horizontal line
(line 16), a vertical line (line 17), and a line (line 18). The getElements() method returns
an ObservableList.
The program creates an ArcTo object (lines 20 and 21). The ArcTo class contains the
largeArcFlag and sweepFlag properties. By default, these property values are false. You
may set these properties to ture to display a large arc in the opposite direction.
The program adds a quadratic curve (line 24) and a cubic curve (lines 25 and 26) and closes
the path (line 28).
By default, the path is not filled. You may change the fill property in the path to specify
a color to fill the path.
31.3.1 Create a QuadCurve with starting point (100, 75.5), control point (40, 55.5), and
end point (56, 80). Set its fill property to white and stroke to green.
31.3.2 Create CubicCurve object with starting point (100, 75.5), control point 1 (40, 55.5),
control point 2 (78.5, 25.5), and end point (56, 80). Set its fill property to white
and stroke to green.
31.3.3 Does a path have a default initial position? How do you set a position for a path? 31.3.4 How do you close a path? 31.3.5 How do you display a filled path?
31.4 Coordinate Transformations
JavaFX supports coordinate transformations using translation, rotation, and scaling.
You have used the rotate method to rotate a node. You can also perform translations and scaling.
31.4.1 Translations
You can use the setTranslateX(double x) , setTranslateY(double y) , and
setTranslateZ(double z) methods in the Node class to translate the coordinates for a
Point
Check
Point
Key
31-10 Chapter 31 Advanced JavaFX and FXML
The program repeatedly creates 10 rectangles (line 17). For each rectangle, it sets its fill
property to white (line 18) and its stroke property to a random color (lines 19 and 20), and
translates it to a new location (lines 21 and 22). The variables x and y are used to set the
translateX and translateY properties. These two variable values are changed every time
it is applied to a rectangle (see Figure 31.8).
31.4.2 Rotations
Rotation was introduced in Chapter 14. This section discusses it in more depth. You can use
the rotate(double theta) method in the Node class to rotate a node by theta degrees
from its pivot point clockwise, where theta is a double value in degrees. The pivot point is
automatically computed based on the bounds of the node. For a circle, ellipse, and a rectangle,
the pivot point is the center point of these nodes. For example, rectangle.rotate(45)
rotates the rectangle 45 degrees clockwise along the eastern direction from the center, as
shown in Figure 31.9.
Figure 31.9 After performing rectangle.rotate(45) , the rectangle is rotated in 45
degrees from the center.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1
3 4
7
5 6
2
After rotate
Before rotate
Rectangle.rotate(45)
Figure 31.8 The rectangles are displayed successively in new locations.
Listing 31.6 gives a program that demonstrates the effect of rotation of coordinates. Figure 31.
shows a sample run of the program.
Listing 31.6 RotateDemo.java
1 import javafx.application.Application; 2 import javafx.scene.Scene; 3 import javafx.scene.layout.Pane; 4 import javafx.scene.paint.Color; 5 import javafx.scene.shape.Rectangle; 6 import javafx.stage.Stage; 7 8 public class RotateDemo extends Application { 9 @Override // Override the start method in the Application class 10 public void start(Stage primaryStage) { 11 Pane pane = new Pane(); 12 java.util.Random random = new java.util.Random();
31.4 Coordinate Transformations 31-
13 // The radius of the circle for anchoring rectangles 14 double radius = 90 ; 15 double width = 20 ; // Width of the rectangle 16 double height = 40 ; // Height of the rectangle 17 for ( int i = 0 ; i < 8 ; i++) { 18 // Center of a rectangle 19 double x = 150 + radius * Math.cos(i * 2 * Math.PI / 8 ); 20 double y = 150 + radius * Math.sin(i * 2 * Math.PI / 8 ); 21 Rectangle rectangle = new Rectangle( 22 x − width / 2 , y − height / 2 , width, height); 23 rectangle.setFill(Color.WHITE); 24 rectangle.setStroke(Color.color(random.nextDouble(), 25 random.nextDouble(), random.nextDouble())); 26 rectangle.setRotate(i * 360 / 8 ); // Rotate the rectangle 27 pane.getChildren().add(rectangle); 28 } 29 30 Scene scene = new Scene(pane, 300 , 300 ); 31 primaryStage.setTitle( "RotateDemo" ); // Set the window title 32 primaryStage.setScene(scene); // Place the scene in the window 33 primaryStage.show(); // Display the window 34 } 35 }
Figure 31.10 The rotate method rotates a node.
The program creates eight rectangles in a loop (lines 17–28). The center of each rectangle is
located on the circle centered as (150, 150) (lines 19 and 20). A rectangle is created by speci-
fying its upper left corner position with width and height (lines 21 and 22). The rectangle is
rotated in line 26 and added to the pane in line 27.
31.4.3 Scaling
You can use the setScaleX(double sx) , setScaleY(double sy) , and setScaleY(double
sy) methods in the Node class to specify a scaling factor. The node will appear larger or
smaller depending on the scaling factor. Scaling alters the coordinate space of the node such
that each unit of distance along the axis is multiplied by the scale factor. As with rotation
transformations, scaling transformations are applied to enlarge or shrink the node around the
pivot point. For a node of the rectangle shape, the pivot point is the center of the rectangle.
For example, if you apply a scaling factor ( x = 2, y = 2), the entire rectangle including the
stroke will double in size, growing to the left, right, up, and down from the center, as shown
in Figure 31.11.
31.5 Strokes 31-
43 Scene scene = new Scene(pane, 450 , 200 ); 44 primaryStage.setTitle( "ScaleDemo" ); // Set the window title 45 primaryStage.setScene(scene); // Place the scene in the window 46 primaryStage.show(); // Display the window 47 } 48 }
Figure 31.12 The scale method scales the coordinates in the node.
The program creates a polyline (line 13) and adds the points for a sine curve into the polyline
(lines 14–17). Since sin( x ) 6 = 1, the y -coordinates are too small. To see the sine curve,
the program scales the y -coordinates up by 50 times (line 21) and shrinks the x -coordinates
by half (line 20).
Note scaling also causes the stroke width to change. To compensate it, the stroke width is
purposely set to 1.0 / 25 (line 22).
31.4.1 Can you perform a coordinate transformation on any node? Does a coordinate trans-
formation change the contents of a Shape object?
31.4.2 Does the method setTranslateX(6) move the node’s x -coordinate to 6? Does the
method setTranslateX(6) move the node’s x -coordinate 6 pixel right from its
current location?
31.4.3 Does the method rotate(Math.PI / 2) rotate a node 90 degrees? Does the
method rotate(90) rotate a node 90 degrees?
31.4.4 How is the pivot point determined for performing a rotation?
31.4.5 What method do you use to scale a node two times on its x -axis?
31.5 Strokes
Stroke defines a shape’s border line style.
JavaFX allows you to specify the attributes of a shape’s boundary using the methods in Figure 31.13.
Point
Check
Point
Key
The setStroke(paint) method sets a paint for the stroke. The width of the stroke can be
specified using the setStrokeWidth(width) method.
Figure 31.13 The Shape class contains the methods for setting stroke properties.
javafx.scene.shape.Shape +setStroke(paint: Paint): void +setStrokeWidth(width: double): void +setStrokeType(type: StrokeType): void
+setStrokeLineCap(type: StrokeLineCap): void +setStrokeLineJoin(type: StrokeLineJoin): void +getStrokeDashArray(): ObservableList +setStrokeDashOffset(distance: double): void
Sets a paint for the stroke. Sets a width for the stroke (default 1). Sets a type for the stroke to indicate whether the stroke is placed inside, centered, or outside of the border (default: CENTERED). Specifies the end cap style for the stroke (default: BUTT). Specifies how two line segments are joined (default: MITER). Returns a list that specifies a dashed pattern for line segments.
Specifies the offset to the first segment in the dashed pattern.
31-14 Chapter 31 Advanced JavaFX and FXML
The setStrokeType(type) method sets a type for the stroke. The type defines whether the
stroke is inside, outside, or in the center of the border using the constants StrokeType.INSIDE ,
StrokeType.OUTSIDE , or StrokeType.CENTERED (default), as shown in Figure 31.14.
Figure 31.15 (a) No decoration for a BUTT line cap. (b) A half circle is added to an
unclosed path. (c) A square with half of the stroke width is extended to an unclosed path.
(a) BUTT (b) ROUND (c) SQUARE
Figure 31.16 Path segments can be joined in three ways: (a) MITER, (b) BEVEL, and
(c) ROUND.
(a) MITER (b) BEVEL (c) ROUND
Figure 31.17 The numbers in the list specify the opaque and transparent segments of the
stroke alternately.
10 20 30 40
… [10.0, 20.0, 30.0, 40.0]
10 20 30 40
10 20 30 40
… [10.0, 20.0, 30.0, 40.0, 50]
50 10 20 30 40 50
Figure 31.14 (a) No stroke is used. (b) A stroke is placed inside the border. (c) A stroke is
placed in the center of the border. (d) A stroke is placed outside of the border.
(a) (b) (c) (d)
Note for the centered style, the stroke is applied by extending the boundary of the node by
a distance of half of the strokeWidth on either side (inside and outside) of the boundary.
The setStrokeLineCap(capType) method sets an end cap style for the stroke. The styles
are defined as StrokeLineCap.BUTT (default), StrokeLineCap.ROUND , and StrokeLine-
Cap.SQUARE , as illustrated in Figure 31.15. The BUTT stroke ends an unclosed path with no
added decoration. The ROUND stroke ends an unclosed side of a path with an added half circle
whose radius is half of the stroke width. The SQUARE stroke ends an unclosed side of a path
with an added square that extends half of the stroke width.
The setStrokeLineJoin method defines the decoration applied where path segments meet.
You can specify three types of line join using the constants StrokeLineJoin.MITER (default),
StrokeLineJoin.BEVEL , and StrokeLineJoin.ROUND , as shown in Figure 31.16.
The Shape class has a property named strokeDashArray of the ObservableList
type. This property is used to define a dashed pattern for the stroke. Alternate numbers in the
list specify the lengths of the opaque and transparent segments of the dashes. For example, the
list [10.0, 20.0, 30.0, 40.0] specifies a pattern as shown in Figure 31.17.
31-16 Chapter 31 Advanced JavaFX and FXML
46 Pane pane = new Pane(); 47 pane.getChildren().addAll(rectangle1, rectangle2, rectangle3, 48 line1, line2, line3, line4); 49 50 Scene scene = new Scene(pane, 610 , 180 ); 51 primaryStage.setTitle( "StrokeDemo" ); // Set the window title 52 primaryStage.setScene(scene); // Place the scene in the window 53 primaryStage.show(); // Display the window 54 } 55 56 // Launch the program from command-line 57 public static void main(String[] args) { 58 launch(args); 59 } 60 }
Figure 31.19 You can specify the attributes for strokes.
miter join (^) bevel join round join square cap
butt cap (^) round cap
dash line
The program creates three rectangles (lines 12–29). Rectangle 1 uses default miter join, rec-
tangle 2 uses bevel join (line 22), and rectangle 3 uses round join (line 29).
The program creates three lines with butt, round, and square end cap (lines 31–41).
The program creates a line and sets dash pattern for this line (line 44). Note the
strokeDashArray property is of the ObservableList type. You have to add
Double values to the list. Adding a number such as 10 would cause an error.
31.5.1 Are the methods for setting a stroke and its attributes defined in the Node or
Shape class?
31.5.2 How do you set a stroke width to 3 pixels? 31.5.3 What are the stroke types? What is the default stroke type? How do you set a
stroke type?
31.5.4 What are the stroke line join types? What is the default stroke line join type? How
do you set a stroke line join type?
31.5.5 What are the stroke cap types? What is the default stroke cap type? How do you
set a stroke cap type?
31.5.6 How do you specify a dashed pattern for strokes?
31.6 Menus
You can create menus in JavaFX.
Menus make selection easier and are widely used in window applications. JavaFX provides
five classes that implement menus: MenuBar , Menu , MenuItem , CheckMenuItem , and
RadioButtonMenuItem.
Point
Check
Point
Key
31.6 Menus 31-
MenuBar is a top-level menu component used to hold the menus. A menu consists of
menu items that the user can select (or toggle on or off). A menu item can be an instance of
MenuItem , CheckMenuItem , or RadioButtonMenuItem. Menu items can be associated with
nodes and keyboard accelerators.
31.6.1 Creating Menus
The sequence of implementing menus in JavaFX is as follows:
1. Create a menu bar and add it to a pane. For example, the following code creates a pane
and a menu bar, and adds the menu bar to the pane:
MenuBar menuBar = new MenuBar(); Pane pane = new Pane(); pane.getChildren().add(menuBar);
2. Create menus and add them under the menu bar. For example, the following creates two
menus and adds them to a menu bar, as shown in Figure 31.20a:
Menu menuFile = new Menu("File"); Menu menuHelp = new Menu("Help"); menuBar.getMenus().addAll(menuFile, menuHelp);
Figure 31.20 (a) The menus are placed under a menu bar. (b) Clicking a menu on the
menu bar reveals the items under the menu. (c) Clicking a menu item reveals the submenu
items under the menu item.
(a) (b) (c)
3. Create menu items and add them to the menus.
menuFile.getItems().addAll( new MenuItem("New"), new MenuItem("Open"), new MenuItem("Print"), new MenuItem("Exit"));
This code adds the menu items New, Open, Print, and Exit, in this order, to the File menu,
as shown in Figure 31.20b.
3.1. Creating submenu items.
You can also embed menus inside menus so the embedded menus become submenus.
Here is an example:
Menu softwareHelpSubMenu = new Menu("Software"); Menu hardwareHelpSubMenu = new Menu("Hardware"); menuHelp.getItems().add(softwareHelpSubMenu); menuHelp.getItems().add(hardwareHelpSubMenu); softwareHelpSubMenu.getItems().add(new MenuItem( "Unix" )); softwareHelpSubMenu.getItems().add(new MenuItem( "Windows" )); softwareHelpSubMenu.getItems().add(new MenuItem( "Mac OS" ));
31.6 Menus 31-
Menu menuFile = new Menu( "File" , new ImageView( "image/usIcon.gif" )); MenuItem menuItemOpen = new MenuItem( "New" , new ImageView( "image/new.gif" )); CheckMenuItem checkMenuItem = new CheckMenuItem( "Check it" , new ImageView( "image/us.gif" )); RadioMenuItem rmiBlue = new RadioMenuItem( "Blue" , new ImageView( "image/us.gif" ));
6. A key accelerator lets you select a menu item directly by pressing the CTRL and the
accelerator key. For example, by using the following code, you can attach the accelerator
key CTRL+N to the Open menu item:
menuItemOpen.setAccelerator( KeyCombination.keyCombination( "Ctrl+O" ));
31.6.2 Example: Using Menus
This section gives an example that creates a user interface to perform arithmetic. The inter-
face contains labels and text fields for Number 1, Number 2, and Result. The Result text field
displays the result of the arithmetic operation between Number 1 and Number 2. Figure 31.
contains a sample run of the program.
Figure 31.22 Arithmetic operations can be performed by clicking buttons or by choosing
menu items from the Operation menu.
Here are the major steps in the program (Listing 31.9):
1. Create a menu bar and add it into a VBox. Create the menus Operation and Exit, and add
them to the menu bar. Add the menu items Add, Subtract, Multiply, and Divide under the
Operation menu and add the menu item Close under the Exit menu.
2. Create an HBox to hold labels and text fields and place it into the VBox.
3. Create an HBox to hold the four buttons labeled Add, Subtract, Multiply, and Divide and
place it into the VBox.
4. Implement the handlers to process the events from the menu items and the buttons.
Listing 31.9 MenuDemo.java
1 import javafx.application.Application; 2 import javafx.geometry.Pos; 3 import javafx.scene.Scene; 4 import javafx.scene.control.Button; 5 import javafx.scene.control.Label; 6 import javafx.scene.control.Menu; 7 import javafx.scene.control.MenuBar; 8 import javafx.scene.control.MenuItem; 9 import javafx.scene.control.TextField; 10 import javafx.scene.input.KeyCombination;
31-20 Chapter 31 Advanced JavaFX and FXML
11 import javafx.scene.layout.HBox; 12 import javafx.scene.layout.VBox; 13 import javafx.stage.Stage; 14 15 public class MenuDemo extends Application { 16 private TextField tfNumber1 = new TextField(); 17 private TextField tfNumber2 = new TextField(); 18 private TextField tfResult = new TextField(); 19 20 @Override // Override the start method in the Application class 21 public void start(Stage primaryStage) { 22 MenuBar menuBar = new MenuBar(); 23 24 Menu menuOperation = new Menu( "Operation" ); 25 Menu menuExit = new Menu( "Exit" ); 26 menuBar.getMenus().addAll(menuOperation, menuExit); 27 28 MenuItem menuItemAdd = new MenuItem( "Add" ); 29 MenuItem menuItemSubtract = new MenuItem( "Subtract" ); 30 MenuItem menuItemMultiply = new MenuItem( "Multiply" ); 31 MenuItem menuItemDivide = new MenuItem( "Divide" ); 32 menuOperation.getItems().addAll(menuItemAdd, menuItemSubtract, 33 menuItemMultiply, menuItemDivide); 34 35 MenuItem menuItemClose = new MenuItem( "Close" ); 36 menuExit.getItems().add(menuItemClose); 37 38 menuItemAdd.setAccelerator( 39 KeyCombination.keyCombination( "Ctrl+A" )); 40 menuItemSubtract.setAccelerator( 41 KeyCombination.keyCombination( "Ctrl+S" )); 42 menuItemMultiply.setAccelerator( 43 KeyCombination.keyCombination( "Ctrl+M" )); 44 menuItemDivide.setAccelerator( 45 KeyCombination.keyCombination( "Ctrl+D" )); 46 47 HBox hBox1 = new HBox( 5 ); 48 tfNumber1.setPrefColumnCount( 2 ); 49 tfNumber2.setPrefColumnCount( 2 ); 50 tfResult.setPrefColumnCount( 2 ); 51 hBox1.getChildren().addAll( new Label( "Number 1:" ), tfNumber1, 52 new Label( "Number 2:" ), tfNumber2, new Label( "Result:" ), 53 tfResult); 54 hBox1.setAlignment(Pos.CENTER); 55 56 HBox hBox2 = new HBox( 5 ); 57 Button btAdd = new Button( "Add" ); 58 Button btSubtract = new Button( "Subtract" ); 59 Button btMultiply = new Button( "Multiply" ); 60 Button btDivide = new Button( "Divide" ); 61 hBox2.getChildren().addAll(btAdd, btSubtract, btMultiply, btDivide); 62 hBox2.setAlignment(Pos.CENTER); 63 64 VBox vBox = new VBox( 10 ); 65 vBox.getChildren().addAll(menuBar, hBox1, hBox2); 66 Scene scene = new Scene(vBox, 300 , 250 ); 67 primaryStage.setTitle( "MenuDemo" ); // Set the window title 68 primaryStage.setScene(scene); // Place the scene in the window 69 primaryStage.show(); // Display the window 70