Presentation is loading. Please wait.

Presentation is loading. Please wait.

Section 15.1. §15.1 Introduction  Suppose you want to develop a GUI application to calculate loan payments:  The user should be able type the pertinent.

Similar presentations


Presentation on theme: "Section 15.1. §15.1 Introduction  Suppose you want to develop a GUI application to calculate loan payments:  The user should be able type the pertinent."— Presentation transcript:

1 Section 15.1

2 §15.1 Introduction  Suppose you want to develop a GUI application to calculate loan payments:  The user should be able type the pertinent values into the corresponding boxes, and then click “calculate”  How can our program tell when the “Calculate” button has been pressed (clicked on), so we can run the code to do the calculation?

3 §15.1 Introduction  Let’s run through a simple example to get a taste of what’s involved. We’ll create a stage with two buttons – “OK” and “Cancel”  When the “OK” button is clicked, we’ll output “OK Button Clicked” on the console  When the “Cancel” button is clicked, we’ll output “Cancel button clicked” on the console

4 §15.1 Introduction  So far, all we have written is procedural code The program’s flow execution is determined by the program’s structure (and perhaps its input)  In event-driven code, the user is responsible for determining what happens next  GUIs use event-driven programming to respond to events: Clicking on a button Selecting a check box or a radio button Clicking on a scroll bar

5 §15.1 Introduction  To respond to a button click, you need to write the code to process the button-clicking action.  The button is an event source object – where the action originates.  You need to create an object capable of handling the action (click) event on a button.  This object is called an event handler, as shown in Figure 15.3 (below)

6 §15.1 Introduction  Not just any ol’ object can be a handler for an action event. To be an action event handler: 1. The object must implement the interface EventHandler, which defines the common behavior for all action handlers 2. The EventHandler object handler must be registered with the event source object using the source.setOnAction(handler) method  The EventHandler interface contains the method handle(ActionEvent) for processing the event -- your handler class must override this method to respond to the event

7 §15.1 Introduction  Listing 15.1 (p. 587) is an event-driven application that we can use to explore the components that have to be in place for event-driven code to work  Normally, I would just refer you to this code, and count on you to walk through it, and the book is usually pretty good about explaining the code examples.  However, because this is our first piece of event- handling code, let’s go through this one in small steps…

8 §15.1 Introduction There’s a LOT going on in this code, and it’s worth carefully exploring some of the details

9 §15.1 Introduction Remember, @Override exists to help keep us from making a mistake that could be hard to find without it Suppose a typo left us with public void Handle rather than public void handle We would get a public void method called Handle, but it would not override handle in the EventHandler interface!

10 §15.1 Introduction Second, these two handler classes ( OKHandlerClass and CancelHandlerClass ) are defined in the same.java file as the main ( Application ) class Early in the semester, I said “one class, one.java source file”. Well, that’s not entirely accurate. Only one class in a.java file can be public, but you can have “helper classes” in the same file as long as they’re not public. Since these classes don’t have any visibility modifier, they have the default visibility - package

11 §15.1 Introduction Third, these two handler classes’ handle methods implement (i.e., are where we put) the functionality we want executed when the (click) event occurs The first one announces (on the console) that the “OK” button was clicked The second one announces (also on the console) that the “Cancel” button was clicked

12 §15.1 Introduction Fourth, the creation of the GUI is just like what we did in Chapter 14: Our class extends Application We create a Pane to contain our UI components (an HBox in this case) Create the components ( Button s), and add them to the Pane Finally, we add the Pane to a Scene, and add the Scene to the Stage, and then show the Stage In procedural code, the program ends when main() ends; however, in event-driven code, the program ends when the GUI closes!

13 §15.1 Introduction Finally, the connection between the UI components and their event handlers is accomplished by registering the handlers First, we instantiate the handlers (the handlers have to exist before they can “answer the phone”) Second, we tell the btOK and btCancel buttons who to “call” when an event occurs ( handler1 and handler2, respectively)

14 Section 15.2

15 §15.2 Events and Event Sources  In event-driven programming, events drive (determine) the program’s execution  An event is a signal (message) that something has happened  Some events (like button clicks, key presses, mouse movements) are triggered by user action  Some events (like timer ticks) can be generated by internal program activities

16 §15.2 Events and Event Sources  In one sense, events are like exceptions:  They’re objects (in java) that correspond to something happening An exception object is created (and thrown) when a problem occurs in our code (an exception). Who “gets” the exception object depends on whether we’re in a try/catch block, or if we’re going to throw it on elsewhere An event object is created (and fired) when something happens in the UI code. Who “gets” the event is whoever is registered as a handler for the object that generated the event (the source)

17 §15.2 Events and Event Sources  EventObject hierarchy:  EventObject has a getSource() method (so do its descendants), so an event handler can tell who generated an event it receives (caller ID)

18 §15.2 Events and Event Sources  Table 15.1 (p. 589) has a partial listing of some User Actions, UI Components, events, and handlers What’s most important for you to take away from this table is that different KINDS of source objects (GUI elements) generate different KINDS of events (e.g., buttons get clicked; not moved, like the mouse), and different kinds of events require different kinds of handlers. Although they both answer the phone and then provide some service, if the event is “Somebody is robbing the bank”, I want a “police” KIND of handler, rather than a “customer service” KIND handler. If the event is “I want to order a dozen golf balls”, I don’t need the SWAT team; I need a customer service handler

19 Section 15.3

20 §15.3 Registering Handlers & Handling Events  In order for an object to be a handler: It must implement (be an instance of) the appropriate event handler interface for the kind of event it handles ○ EventHandler must be implemented by Button event handlers, because Button s will fire ActionEvent s. The EventHandler interface forces us to provide handle(ActionEvent e) It (the handler) must be registered to the source object (the method to do the registration depends on the kind of event it’s registering; for an ActionEvent, it’s setOnAction ; for a keypress, it’s setOnKeyPressed ) When an event occurs, the source notifies (sends a message or “places a phone call” to) every listener registered by invoking its handler method

21 §15.3:Registering Handlers & Handling Events  Let’s revisit how this worked in the previous program (Listing 15.1, p. 587): // Create the button line 16): Button btOK = new Button("OK"); // Create handler to receive button’s events (18): OKHandlerClass handler1 = new OKHandlerClass(); // Register the handler with the button (line 19) // This tells the button where to send ActionEvents btOK.setOnAction(handler1);

22 §15.3:Registering Handlers & Handling Events  The text walks through the incremental build of a program to display a circle, and a GUI with two buttons – one to enlarge the circle, and one to shrink the circle (Fig. 15.6):  First, we write the code to create our GUI by extending Application, adding a Pane, and adding the (inert for now) Button s to the UI:

23 §15.3 Registering Handlers & Handling Events Our program starts by extending Application, and overriding the start method, where we build the UI The Circle goes into a StackPane The two Button s get created and put into an HBox pane The StackPane with the Circle goes into the middle section of a BorderPane, and the HBox with the two Button s goes into the bottom section. Finally, add the BorderPane to the Scene, and the Scene to the Stage, and make the Stage visible That gets the UI created, but nothing is configured to handle events (yet)

24 §15.3:Registering Handlers & Handling Events  This code is being written incrementally (which is often a good way to write code; rarely can we see everything we need to do from the starting line).  So, what’s next?  Since the circle need to be able to respond to requests to resize, it should have enlarge and shrink methods  Since the resizable circle will have its own methods, it should be its own class, rather than just being a shape inside some other class

25 §15.3 Registering Handlers & Handling Events The new CirclePane class will be an extension of a StackPane that contains the circle Again, because we are not defining a second public class, this package-level-visibility class can reside in the same.java source file. Because it’s an extension of the StackPane, the CirclePane can access its own list of children, and add a circle in its constructor The CirclePane ’s enlarge and shrink methods simply add or subtract 2 to the circle’s current radius. In the shrink method, it checks before subtracting 2 to make sure it’s over 2 (the radius can’t go negative, and it’s probably a good idea to keep it from going to zero, so > 2, as opposed to >= 2, is a wise idea.

26 §15.3 Registering Handlers & Handling Events Armed with our new, fully-functional CirclePane class, we can just make it a field of the ControlCircle class. We instantiate it as we declare it When we build the BorderPane, we add the CirclePane to its center section, just a before

27 §15.3 Registering Handlers & Handling Events Now things get a bit more interesting. We know that the Button s will need a class they can fire their events to. We create the EnlargeHandler class to handle the ActionEvent s that will come from the “Enlarge” Button. The EnlargeHandler class has a handle method, which will only have to call the CirclePane ’s enlarge method. Look closely, and you’ll realize that the ControlCircle class runs from line 14 to 49 The EnlargeHandler class runs from line 43 through line 48 – it’s INSIDE the ControlCircle class! WHAT !?!

28 §15.3 Registering Handlers & Handling Events So far, classes have contained fields and methods, period. In this example, we have a class that also contains another class. This nesting of classes is called creating an inner class. We’ll talk more about this in the next section. One of the reasons to have the inner class is related to variable scope. Because circlePane is a field, its scope is class-wide, so inside the EnlargeHandler ’s handle method, circlePane is in-scope, so we can see it to call its enlarge method

29 §15.3 Registering Handlers & Handling Events So, now that we have a handler class for our “enlarge” Button, we need to instantiate it and tell the button to send its ActionEvents to it. Line 29 does both in one shot This code, as-written, doesn’t have any provision for the shrink button. The book leaves that as an exercise, but by now, it should be obvious what we need to do: Create a second inner class, ShrinkHandler, that works just like EnlargeHandler, except that its handle method should call the circlePane ’s shrink method, rather than its enlarge method. The other thing we need to do is to instantiate the ShrinkHandler class, and register it with the “shrink” Button. This is just a copy of line 29, except that it’s btnShrink and new ShrinkHandler()

30 Section 15.4

31 §15.4 Inner Classes  An inner class (which we used in the preceding section without really talking about) is a class defined within the scope of another class They are sometimes called nested classes.  Inner classes are useful for defining listener (event-handling) classes  The class within which the inner class is defined is called, appropriately enough, an outer class  Normally, you define an inner class when it will be used by only the outer class

32 §15.4 Inner Classes  Inner classes can help make your source files easier to manage public class Test { … } public class A { … } Test.java  Test.class A.java  A.class public class Test { … // inner class class A { … } Test.java  Test.class and  Test$A.class

33 §15.4 Inner Classes  The inner class can reference fields and methods of the outer class directly, so you don’t need to pass references from the outer class to the inner class Avoiding this potentially cumbersome reference issue can make your programs more simple and concise.  “A listener class is designed specifically to create a handler object for a GUI component (e.g., a button). The handler class will not be shared by other applications and therefore is appropriate to be defined inside the main class as an inner class.”

34 §15.4 Inner Classes  See the other rules and nuances regarding inner classes on p. 594.  For our purposes, most of these are immaterial  We will be using inner classes to create handlers for UI elements in the outer class.

35 Section 15.5

36 §15.5 Anonymous Inner Classes  “An anonymous inner class is an inner class without a name. It combines defining an inner class and creating an instance of the class into one step”  Uhhhh?  Back when we introduced arrays, we had and example of creating an anonymous array to pass to a method (next slide):

37 §7.6 Passing Arrays to Methods public static void printArray(int[] array) { for (int i = 0; i < array.length; i++) System.out.print(array[i] + " "); } Invoke the method: int[] list = {3, 1, 2, 6, 4, 2}; printArray(list); Invoke the method: printArray(new int[] {3, 1, 2, 6, 4, 2}); “Anonymous array”

38 §15.5 Anonymous Inner Classes  An anonymous inner class is handled pretty much the same way  Rather than having the definition of the class (the code that makes up the class) one place,…  …a declaration of an instance variable and an instantiation (with new) someplace else, just so we can pass a reference to an instance of the class to some other method, …  We can use an anonymous inner class.

39 §15.5 Anonymous Inner Classes  We have seen anonymous objects (such as.setForeground(new Color(Color.RED) ), which perform an instantiation and pass the reference to some method, rather than storing it in a reference variable and passing that.  An anonymous inner class combines a class’s definition and instantiation in one step:

40 §15.5 Anonymous Inner Classes public void start(Stage primaryStage) { // Several Lines Omitted btnEnlarge.setOnAction(new EnlargeHandlner()); } // EnlargeHandler as an inner class class EnlargeHandler implements EventHandler { @Override public void handle(ActionEvent e) { circlePane.enlarge(); }

41 §15.5 Anonymous Inner Classes public void start(Stage primaryStage) { // Several Lines Omitted btnEnlarge.setOnAction(new EnlargeHandlner()); } // EnlargeHandler as an inner class class EnlargeHandler implements EventHandler { @Override public void handle(ActionEvent e) { circlePane.enlarge(); }

42 §15.5 Anonymous Inner Classes public void start(Stage primaryStage) { // Several Lines Omitted btnEnlarge.setOnAction(new EnlargeHandlner()); } // EnlargeHandler as an inner class class EnlargeHandler implements EventHandler { @Override public void handle(ActionEvent e) { circlePane.enlarge(); }

43 §15.5 Anonymous Inner Classes public void start(Stage primaryStage) { // Several Lines Omitted btnEnlarge.setOnAction(new EnlargeHandlner()); } // EnlargeHandler as an inner class class EnlargeHandler implements EventHandler { @Override public void handle(ActionEvent e) { circlePane.enlarge(); }

44 §15.5 Anonymous Inner Classes public void start(Stage primaryStage) { // Several Lines Omitted btnEnlarge.setOnAction(new EventHandler { @Override public void handle(ActionEvent e) { circlePane.enlarge(); } }); }

45 §15.5 Anonymous Inner Classes  Since an anonymous inner class is a special kind of inner class, it is treated like an inner class with the following four features: 1. An anonymous inner class must always extend a superclass or implement an interface, but it cannot have an explicit extends or implements clause. 2. An anonymous inner class must implement all the abstract methods in the superclass or in the interface (it must “go concrete”).

46 §15.5 Anonymous Inner Classes  Since an anonymous inner class is a special kind of inner class, it is treated like an inner class with the following four features: 3. An anonymous inner class always uses the no-arg constructor from its superclass to create an instance. If an anonymous inner class implements an interface, the constructor is Object(). 4. An anonymous inner class is compiled into a class named OuterClassName$n.class. For example, if the outer class Test has two anonymous inner classes, they are compiled into Test$1.class and Test$2.class.

47 §15.5 Anonymous Inner Classes  In Listing 15.4 (pp. 595-596, and next slide), Liang shows the code for an application with four buttons.  When each button is clicked, it produces output on the console (although we can certainly have its click event handler do anything we want):

48 §15.5 Anonymous Inner Classes I’ve omitted the import statements from the top Lines 14 – 21 create an HBox and four Button s, which it adds to the HBox. The “New” button ( btnNew ) needs to be registered with the object that will receive (and handle) its ActionEvents. That object will have to be an instance of a class that inplements EventHanlder That’s precisely what the blue-shaded code in lines 24 – 29 IS The same format is repeated to register an anonymous inner EventHandler class for btnOpen, btnSave, and btnPrint By “embedding” the handler classes inside the class with the UI, we eliminate the need for several explicitly-defined classes that will be used only to handle events for one object!

49 Section 15.6

50 §15.6 Lambda Expressions and Events  Lambda Expressions (new to Java 8) can be considered an anonymous inner class with an abbreviated syntax.  The compiler treats lambda expressions like an object created from an anonymous inner class

51 §15.6 Lambda Expressions and Events  The compiler knows that the parameter of the setOnAction method must be something of type EventHandler, and that particular interface has only one abstract method, so the code between the braces must be the statements for that method  Let’s revisit the anonymous inner class handler:

52 §15.6 Lambda Expressions and Events In the original code, each button had its own complete anonymous inner class to handle the ActionEvent from its corresponding button In the updated version, we show four different ways (styles) of expressing the registration of the event handler using lambda expressions The first explicitly gives the type of e The second omits the type, because the compiler can infer that e is of type ActionEvent The third omits the parentheses, because there is only one parameter The fourth omits the braces, because there is only one line of code (much like a one-line then or else clause of an if / then / else, or a one-statement loop body) Lambda expressions make for cleaner code!

53 Section 15.7

54 §15.7: Case Study: Loan Calculator  This chapter began with:  Suppose you want to develop a GUI application to calculate loan payments:  This section builds this program, start-to-finish  We introduce the TextField node – a box into which we can type text  The Monthly Payment and Total Payment fields are display-only (the user can’t type In these)  Let’s take a closer look at this code…

55 §15.7: Case Study: Loan Calculator Seventy-five lines of code simply isn’t readable at this size, so we’ll go through this program in pieces

56 §15.7: Case Study: Loan Calculator Lines 1 – 9 simply import the JavaFX components we will need for this program

57 §15.7: Case Study: Loan Calculator Lines 11 – 17 begin our LoanCalculator class (an extension of Application ), and create the five TextField s (and the “Calculate” Button ) as fields of the class These are set up as fields so that the method to do the calculation (see below) can see them, and we don’t have to pass them all as parameters (by making them fields, they have class-wide scope)

58 §15.7: Case Study: Loan Calculator Line 20 begins our code, with an override of start Lines 22 – 35 set up a 5-x-2 GridPane, with Label s (left side) and TextFields (right side) for the first 4 rows The 5 th row holds only the “Calculate” Button, right- justified in the right column (nothing in the left column)

59 §15.7: Case Study: Loan Calculator Line 38 centers the GridPane in its Scene Lines 39 – 43 cause the text in the TextFields to be right-justified within the fields Lines 44 – 45 keep the user from being able to edit (type inside of) those two TextFields (we’re going to calculate their values and fill them in via code; the user shouldn’t be able to enter anything in them) Line 46 right-aligns the “Calculate” Button in its grid cell

60 §15.7: Case Study: Loan Calculator Line 49 uses a Lambda Expression to register the “Calculate” Button to its handle method (located in the implicit anonymous inner class), which contains a single line of code – a call to the calculateLoanPayment method

61 §15.7: Case Study: Loan Calculator Lines 51 – 56 form the typical end of the start method: The container for our UI elements (the GridPane ) is added to a new Scene (l. 52), which is added to the Stage (l. 54). The Stage is given a title (l. 53), and made visible (l. 55)

62 §15.7: Case Study: Loan Calculator Line 49 registers a call to calculateLoanPayment as the handler for the “Calculate” Button ’s ActionEvent. This is that code. In order to do the calculations, we need the values to be in numeric variables, but the TextField boxes all hold String s, so we have to parse them into numeric variables first (ll. 60-64)

63 §15.7: Case Study: Loan Calculator Once we have the numeric versions of the String s in the three TextField s, we can use those to create a Loan object (see Listing 10.2, pp. 368 – 369) – l. 67 Once instantiated, the Loan class provides the methods getMonthlyPayment() and getTotalPayment() to give us the values to display in the last two TextField s (ll. 70 – 73).

64 Section 15.8

65 §15.8: Mouse Events  Mouse events are fired whenever the mouse… …button goes down ( MousePressed ) …button comes back up ( MouseReleased ) …button is clicked (a down/up cycle – MouseClicked ) …first enters an element ( MouseEntered ) …leaves an element ( MouseExited ) …moves while over an element ( MouseMoved ) …is dragged (moved with the mouse button held down – MouseDragged )  These events are from Table 15.1 (p. 589)

66 §15.8: Mouse Events  All mouse events have some common methods we can use to tell more about the state / location of the mouse and the keyboard’s Alt / Control / Shift / Meta (Mac) keys:

67 §15.8: Mouse Events  JavaFX (currently) supports 3 buttons, left, middle, and right (some mice have more)  We can tell which mouse button was pressed by using the MouseEvent ’s getButton() method and comparing the result to: MouseButton.PRIMARY, MouseButton.SECONDARY, MouseButton.MIDDLE, or MouseButton.NONE NONE is on the list simply because some mouse events (like MouseMoved ) don’t involve a button

68 §15.8: Mouse Events  The book presents a sample program that lets the user drag (click, holding the primary (left?) mouse button down, and moving the mouse before releasing the button) a Text node around on the pane:  The (surprisingly short) code is on the next slide

69 §15.8: Mouse Events When the mouse is dragging the text, set the text’s X/Y location to the X/Y location of the mouse (which we get from the event, e)

70 Section 15.9

71 §15.9: Key Events  The user can also interact with the GUI through the keyboard.  We can capture (handle) events that are generated by the keyboard on a key-by-key basis, without having to wait for the user to press Enter, as we do with the Scanner  We can tell when keys go down ( KEY_PRESSED ), come back up ( KEY_RELEASED ), or make a down-and-up round-trip ( KEY_TYPED )  We can also tell if the SHIFT, ALT, CONTROL, or META (Mac) keys are down at the same time ( isShiftDown(), isAltDown(), …)

72 §15.9: Key Events  Not all keys generate a character we can display (some don’t generate a character at all!)  For the KEY_PRESSED and KEY_RELEASED events, e.getCode() tells us which key was pressed or released (whether or not it generates a character) Typically used for non-character-generating keys like the cursor keys ( KeyCode.UP, KeyCode.PAGE_DOWN, etc.). See here for the full listhere

73 §15.9: Key Events - Demo  The KeyEventDemo program (Listing 15.8, pp. 604 – 605, and next slide) starts with a window (Stage) containing “A”  If the user types a letter or digit, it replaces the character displayed.  If the user presses the UP, DOWN, LEFT, or RIGHT cursor-movement keys, the letter moves in the corresponding direction by 10 pixels.

74 §15.9: Key Events - Demo When our Text node receives a KeyPressed event, if it’s UP, DOWN, LEFT, or RIGHT, move the text 10 pixels in the proper direction. If it’s none of those four, but it IS a letter or digit, then change the content of the Text node to whatever the key was. How do we know our Text node (as opposed to some other node, if we had more on the pane) will receive the key press? We give it the focus (see p. 605)

75 §15.9: Key Events  Listing 15.9 (pp. 605 – 606, and next slide) adds key and mouse controls to the enlarge / shrink Circle project  The original version allowed ONLY the buttons to enlarge or shrink the circle’s radius  Now we add the ability to have the “U” and “D” keys to take the radius “U”p and “D”own by having the CirclePane handle KeyPress events  We also let the left / right mouse buttons do the same thing  Again, we make sure the CirclePane object receives key events by giving it the focus

76 §15.9: Key Events Listing 15.9 (pp. 605 – 606) adds key and mouse controls to the enlarge / shrink Circle project The original version allowed ONLY the buttons to enlarge or shrink the circle’s radius Now we add the ability to have the “U” and “D” keys to take the radius “U”p and “D”own by having the CirclePane handle KeyPress events:

77 §15.9: Key Events The left and right mouse buttons can now do the same thing: Again, we make sure the CirclePane object receives key events by giving it the focus (l. 58)

78 §15.9: Key Events  A minor point to note: When you click on a button, it (the button) receives the focus So, in our last example, if we click on the “Enlarge” button, the button will get (and keep) the focus That means that a “D” or a “U” won’t GO to the CirclePane – it will go to the last button that was pressed! To fix this, add circlePane.requestFocus() to the end of both button-click handlers (between lines 31/32 and lines 34/35)

79 Section 15.10

80 §15.10: Listeners for Observable Objects  Liang does a terrible job of explaining what this topic is all about.  In Chapter 14, we showed how to bind one property to another, so that when one changed in value, that change would get forwarded to the one it was bound to (unidirectional binding)  We also saw how to do bidirectional binding, and a change to either would change the other.

81 §15.10: Listeners for Observable Objects  This property binding is sort of a limited form of what we’re talking about in this section, but rather than one property changing another, when a property changes in value, it fires an event, which we can handle  The implications here are huge  Rather than one property just automatically forcing a change in another (which is already plenty useful), we can have the even handler’s code do whatever we want, potentially a LOT more than just changing another property.

82 §15.10: Listeners for Observable Objects  So, when we have an observable object (i.e., one that implements the Observable interface), we can observe (“keep an eye on”, or more accurately, “listen to”) a property, and when the property’s value changes, an event will fire (which, obviously, we will handle).  In order to “listen to” the property we want to monitor, we have to use the.addListener method to tell it who to notify when the property changes.

83 §15.10: Listeners for Observable Objects  The object that does the listening must implement InvalidationListener, which means it has an invalidated method that takes an Observable property o as its parameter.  Binding properties are Observable, so the same kinds of things we were doing with bound properties can be used to fire invalidated methods to invoke code when the property changes value.

84 §15.10: Listeners for Observable Objects  Listing 15.10 (p. 607) is a rather contrived example of how this works.  balance is instantiated as a property (not a property of anything in particular; just some property) – Line 8  Lines 9 – 14 register a listener for this property. This is done with an anonymous inner class that implements the invalidated method, which displays the property’s new value on the console  Lambda expressions make doing handlers easier, so in the middle of the page, we see the inner class replaced with a Lambda expression

85 §15.10: Listeners for Observable Objects  So, with all of this set up, when line 16 runs (the property we’re observing receives a new value), the event fires, and “ The new value is 4.5 ” gets printed.

86 §15.10: Listeners for Observable Objects  The book next provides a somewhat more practical example  The analog clock face we built in Chapter 14 did not resize when the window was resized  If we “listen to” the window’s size, and then fire an event when it changes, the code we connect to that change can resize the clock face  The program in listing 15.11 (pp. 607 – 608) does exactly that.

87 §15.10: Listeners for Observable Objects  It’s the same as Listing 14.20 (which just displays the face), except for lines 29 – 35, which were added to listen to the pane’s width and height:  When either the pane’s height or width changes, rather than binding one property to another (which could also have solved this problem), we execute code to set the clock’s height / width.

88 Section 15.11

89 §15.11: Animation  JavaFX gives us the Animation class, which has the core functionality for all animation  Animation is an abstract class with the core functionality  We will want to use one of its concrete subclasses to actually get specific things done.  The subclasses we will look at are: PathTransition FadeTransition, and Timeline  First, let’s take a look at Animation :

90 §15.11: The Animation Class  If cycleCount is 1, the animation happens once  If cycleCount is 2, and autoReverse is true, the animation goes forward and backward (once)  A cycleCount of Timeline.INDEFINITE runs forever  A rate of 1.0 is normal speed; 2.0 is 2x; -1.0 means run backwards

91 §15.11.1: PathTransition  A Duration object defined a duration of time.  Typically, you’ll want to stick with milliseconds (see pp. 609 – 610 for more details and options)  The orientation can be set to keep the node rotated perpendicular to its path as it moves

92 §15.11.1: PathTransition  We get two examples of using a PathTransition to move some other node along.  In Listing 15.13 (pp. 611 – 612), the U.S. flag is raised five times  At the end of a “raising”, it’s not lowered; it jumps back to the bottom (the starting point for the animation) and the next cycle begins  At the end of the last cycle, the animation stops, and the flag stays at the top of the pane.

93 §15.11.1: PathTransition public void start(Stage primaryStage) { // Create a pane Pane pane = new Pane(); // Add an ImageView containing the U.S. flag, and add it to the pane ImageView imageView = new ImageView("image/us.gif"); pane.getChildren().add(imageView); // Create a path transition for the flag to move along, and start it: PathTransition pt = new PathTransition(Duration.millis(10000), // 10 sec new Line(100, 200, 100, 0), // vertical line imageView); // what to move along that line pt.setCycleCount(5); // run for 5 cycles pt.play(); // Start animation // Create a scene and place it in the stage Scene scene = new Scene(pane, 250, 200); primaryStage.setTitle("FlagRisingAnimation"); // Set the stage title primaryStage.setScene(scene); // Put scene in stage primaryStage.show(); // Display the stage } // end of start method

94 §15.11.1: PathTransition  A somewhat more involved example is shown in Listing 15.12, (pp. 610 – 611).  The UI is straightforward – we create a white- filled black circle and an orange-filled rectangle, and add those nodes to a pane (ll. 16 – 29)

95 §15.11.1: PathTransition  Lines 32 – 40 are where the fun comes in  The rectangle will move (l. 35) along the circle’s circumference (l. 34), and will take 4 seconds to go around (l. 33), at which point it will reverse direction and go back for 4 seconds (l. 39). This action repeats until the program is closed (l. 38).  The rectangle is rotated to keep it perpendicular to the circle’s circumference (ll. 36 – 37).  Finally, we capture the MousePressed and MouseReleased events from the circle, and pause and resume the animation (ll. 42 – 43)

96 §15.11.2: FadeTransition  The FadeTransition class animates the change of the opacity of a node over time  We can specify the starting, ending, and increment values for the opacity

97 §15.11.2: FadeTransition  Listing 15.14 (pp. 612 – 613) shows a program that displays a red-filled black-stroked ellipse (ll. 16 – 18), whose center and size are bound to the size of the pane (ll. 19 – 25).  A 3-second FadeTransition is applied to the ellipse, taking it from opaque to 90% transparent and back, over and over indefinitely (ll. 28 – 34)  MousePressed / MouseRelease pauses / resumes the animation (ll. 37 – 38)

98 §15.11.3: Timeline  The PathTransition is a somewhat limited animation, because it only allows a single node to be moved in a particular path  The FadeTransition is also rather limited, as all it does is change the opacity of a node.  The Timeline animation is more flexible, because it works with one or more KeyFrame s  A KeyFrame is constructed with a Duration and an EventHandler to be executed when the Duration expires

99 §15.11.3: Timeline  Listing 15.15 provides the code for an example that displays flashing text.  The Timeline has a single KeyFrame, which has a Duration of 500 ms.  When the KeyFrame ’s Duration expires, the eventHandler method changes the contents of the Text node: If it’s empty, it gives it a message; if it has a message, it makes it empty.  This toggling effect, coupled with the fact that the animation runs INDEFINITE ly, means that the text will appear to be blinking.  Similarly, mouse clicks toggle pause / resume

100 §15.11.3: Timeline  Liang wraps up the Timeline discussion by extending the clock face demo from §14.12.  In Chapter 14, we learned how to use the pane, circle, and line nodes to display a clock face, but it was static – we didn’t know how to animate it to get it to update the time every second  Now we do  Listing 15.16 (pp. 615 – 616) uses this same Timeline / KeyFrame approach to basically fire an event every second, which will be used to set the clock’s time, causing a re-draw of the hands

101 §15.11.3: Timeline public class ClockAnimation extends Application { @Override // Override the start method in the Application class public void start(Stage primaryStage) { ClockPane clock = new ClockPane(); // Create a clock face // Create a handler for animation EventHandler eventHandler = e -> { clock.setCurrentTime(); // Set a new clock time }; // Create an animation for a running clock Timeline animation = new Timeline( // With one repeated keyframe, new KeyFrame(Duration.millis(1000), // every second, we will run eventHandler)); // eventHandler to update time animation.setCycleCount(Timeline.INDEFINITE); animation.play(); // Start animation // Create a scene and place it in the stage Scene scene = new Scene(clock, 250, 50); primaryStage.setTitle("ClockAnimation"); // Set the stage title primaryStage.setScene(scene); // Put scene in stage primaryStage.show(); // Display the stage }

102 Section 15.12

103 §15.12: Bouncing a Ball  Finally, we tie together Timeline animation, key events, and mouse events in the Bouncing Ball demo.  This program consists of two classes – one to simulate the ball itself, and another to control the ball (start / stop / speed up / slow down)  Let’s look first at BounceBallControl (p. 619)

104 §15.12: BounceBallControl Class public void start(Stage primaryStage) { BallPane ballPane = new BallPane(); // Create a ball pane // Note: The ball animates itself using a Timeline; we don’t have to do // things like move it around here; all we do here is start / stop and // speed up / slow down. See the BallPane class for the other details // Pause and resume animation ballPane.setOnMousePressed (e -> ballPane.pause()); // mouse down  pause ballPane.setOnMouseReleased(e -> ballPane.play()); // mouse up  resume // Increase and decrease animation with key presses ballPane.setOnKeyPressed(e -> { // respond to only UP and DOWN if (e.getCode() == KeyCode.UP) ballPane.increaseSpeed(); else if (e.getCode() == KeyCode.DOWN) ballPane.decreaseSpeed(); }); // Create a scene and place it in the stage Scene scene = new Scene(ballPane, 250, 150); primaryStage.setTitle("BounceBallControl"); // Set the stage title primaryStage.setScene(scene); // Put scene in stage primaryStage.show(); // Display the stage // Must request focus after the primary stage is displayed ballPane.requestFocus(); }

105 §15.12: BallPane Class Lines 1 – 7 simply import the JavaFX components we will need for this program

106 §15.12: BallPane Class Lines 9 – 14 define the fields for the BallPane class. The ball’s radius is fixed at 20 pixels Its x and y location starts out at radius, so it’s located just inside the pane’s top-left corner dx and dy indicate which direction the ball is moving We’ll set dx to +1 / -1 to move right / left, resp. We’ll set dy to +1 / -1 to move down / up, resp. These items are all set up as fields to give them class-wide scope, so that the various methods can see them

107 §15.12: BallPane Class In the BallPane ’s constructor, we color the circle (which we couldn’t do when we declared it on l. 13), and add it to the pane Next, we create a Timeline animation with a single 50-ms KeyFrame. Every time the KeyFrame expires, (20 times per second), we will call moveBall to update the ball’s position. The animation will run indefinitely, and we start it.

108 §15.12: BallPane Class Similarly, increaseSpeed() and decreaseSpeed() are called from BounceBallControl as a result of a key press. increaseSpeed() will add 10% to the speed decreaseSpeed() will subtract 10% from the speed, but only if the speed is already positive. Otherwise, it sets the speed to zero (frozen).

109 §15.12: BallPane Class The rateProperty() method is of zero use to us in this program as it stands, but will be used in the next chapter, when we will use it to bind to, so we’ll go ahead and define it now.

110 §15.12: BallPane Class Finally, moveBall() actually moves the ball when the KeyFrame expires (every 50 ms – see line 22). If the ball has tried to move left of the left border, or right of the right border, then we reverse its direction by negating the sign on dx. We do the same for dy with respect to the top/bottom. Finally we move x and y (in some direction) by one pixel, and move the circle’s center to the new x, y

111 End of Chapter 15 Any Questions?


Download ppt "Section 15.1. §15.1 Introduction  Suppose you want to develop a GUI application to calculate loan payments:  The user should be able type the pertinent."

Similar presentations


Ads by Google