Explanation Component has Operation( ), which is a method that applies to all components, whether composite or leaf. There are generally many operations. Component also has composite methods: Add( ), Remove( ), and GetChild( ). Note that in all cases a Component is passed. Component itself just throws an exception for these methods. Leaf implements the operations. Does nothing on Component methods, which just return. Composite implements the composite methods. Also implements the operations, by invoking the operation on each of its children in succession. Composite Pattern Diagram The composite pattern lets us treat an object (the Component) as if it could be a Leaf (contains no children) or a Composite, made up of a number of leaves and/or composites. JavaFX: Node Node is something that goes in a Parent Since a Parent isa Node, you get a hierarchy Some functionality the Node class provides to its descendants: Painting (how an object is displayed), borders Application-wide pluggable look and feel Support for layout (where in the container does it go?) Support for accessibility (mouse and keyboard) Some example descendants of Node are: (many kinds of) Pane, Button, ListView, Label, and many more. JavaFX Subclass Hierarchy, cont. Object Parent Pane getchildren() GridPane FlowPane VBox BorderPane HBox JavaFX Layout Classes Top-Level Containers To appear onscreen, every GUI component must be added to a top-level container. The top-level container corresponds to what you think of as a window or application on your computer. A containment (has-a) hierarchy for a simple GUI: Stage Scene Parent top-level container components GridPane Label Menu MenuItem 1
Event-Driven Programming A style of coding where a program's overall flow of execution is dictated by events: The program loads The program waits for the user to generate input Each event causes some particular code to respond Need an event handler The overall flow of what code is determined by the user generating a series of events Event-Driven Programming We contrast this with the types of programs that we have been producing so far, which we might term: prompt-and-wait style programs Event-Driven Programming The main body of the program is an event loop The main algorithm abstractly: do { e = getnextevent(); processevent(e); while (e!= quit); Kinds of Events Different events that can occur in an event-driven program with a GUI Mouse move/drag/click, mouse button press/release Keyboard: key press/release Touchscreen finger tap/drag Joystick, drawing tablet, other device inputs Window resize/minimize/restore/close Network activity or file I/O (start, done, error) Timer interrupt Move a scroll bar Chose a menu selection Media finishes handle(event) Java s Event Model Java and the operating system work together to detect user interaction Button objects are notified when clicked Send a handle(actionevent) message to registered ActionEvent handlers TextField objects are notified when the user presses Enter A handle(actionevent) message is sent to registered event handlers When the mouse is clicked, the node under the curser is notified Send a handle(mouseevent) message to registered Mouse event handlers When a key is pressed Send a handle(keyevent) message to registered KeyEvent handlers Example: ActionEvent The button and textfield do not yet perform any action Let s make something happen when The button is clicked The user presses enters into the textfield 2
How to Handle Events Add a private inner class that will handle the event that the component generates This class must implement an interface to guarantee that it has the expected method such as public void handle(actionevent ae) Register the event handler so the component can later send the correct message to that event handler Events occur anytime in the future--the event handler is waiting for user generated events such as clicking button Send this message to the GUI component: button.setonaction(handler); Using an Inner Class Have a private inner class that implements EventHandler <ActionEvent>: EventHandler<ActionEvent> handler = new ButtonHandler(); button.setonaction(handler); private class ButtonHandler implements EventHandler<ActionEvent> { @Override public void handle(actionevent event) { button.settext(textfield.gettext()); Using a Lambda JavaFX Input: Inversion Of Control EventHandler<ActionEvent> handler = new ButtonHandler(); button.setonaction((event) -> { button.settext(textfield.gettext()); ); Using Blocking/Polling: Application calls a method and waits (blocks) for input from the user: // Waits for user input, polling... inputstring = myscanner.nextline(); Using Callbacks: the programmer indicates what methods, specified in EventHandlers and other event listener classes) are to be called passed certain input events (or ActionEvents). These methods are called callbacks because the application is telling JavaFX to call it back should a given event occur JavaFX is in control and delegates control, based on input, to the application code. Hence the term Inversion Of Control. Observer Design Pattern Observer Design Pattern Observer is a software design pattern in which the model maintains a list of its observers, and notifies them automatically of any state changes It is the heart of MVC This is what we will use to have multiple views (ButtonView, TextAreaView, DrawingView) observe the model and change when the model changes Both views must be added as "Observers" The model is the "Observable" A specific message from an interface is sent to all observers in these methods of Patterns in TTT TicTacGame() startnewgame() choose(int row, int col) Observer is used so frequently that Java supplies A class to be extended: Observable An interface to be implemented by many classes: Observer 3
Observer Design Pattern The Model's Responsibilities /** Use a Pane to implement this interface so the Pane can show a view of the model and allow user input */ public class ButtonView extends BorderPane implements Observer // This method is called by Observable's notifyobservers() public void update(observable observable, Object message) { thegame = (TicTacToeGame) observable; updatebuttons(); if (thegame.didwin('x')) statebutton.settext("x wins"); else if (thegame.didwin('o')) statebutton.settext("o wins"); else if (thegame.tied()) statebutton.settext("tie"); else statebutton.settext(clickmessage); Provide access to the state of the model didwin(char), getat(int, int), Provide access to the system's functionality startnewgame(), setcomputerplayerstrategy(tictactoestrategy) Notify the view(s) that the model's state has changed /** * This is called from humanmove when not testing */ public void computermove(int row, int col) { if (board[row][col]!= '_') return; board[row][col] = 'O'; setchanged(); //Java needs this or notifyobservers does nothing notifyobservers(); //Send update messages to all Observers The Controller Responsibilities Full MVC Architecture Respond to user input (when an event occurs) Button click in ButtonView or enter integers in the TextArea with a button click (a view that you are asked to implement) Send makemove() messages to the model our TicTacToeGame), that sends notifyobservers() messages to the Observable (TicTacToeGame) that sends update messages to the observers In JavaFX, our EventHandlers are controllers Notifies upon user interaction View Controller Model Updates Triggers changes in The Canvas Node Drawing Text JavaFX added a Canvas Node to mimic HTML5's Canvas Add a Canvas object to a Pane allows a portion of our application to be viewed as an image We can the draw shapes and images Canvas objects have a width and height public void start(stage stage) { BorderPane pane = new BorderPane(); Canvas canvas = new Canvas(200, 100); pane.setcenter(canvas); GraphicsContext gc = canvas.getgraphicscontext2d(); // This string will be drawn 20 pixels right, // 40 pixels down as the lower left corner. // All other shapes point is the upper left gc.filltext("i'm in a Canvas", 20, 40); Need to draw onto the GraphicsContext object of the Canvas object (see code on the next slide) Scene scene = new Scene(pane, 200, 100); stage.setscene(scene); stage.show(); 4
The Coordinate System The Coordinate System A simple two-dimensional coordinate system exists for each graphics context, or drawing surface <0, 0> x X Each point on the coordinate system represents a pixel y <x, y> Top left corner of the area is coordinate <0, 0> // This string will be drawn 20 pixels right, // 40 pixels down as the lower left corner. gc.filltext("i'm in a Canvas", 20, 40); A drawing surface has a width and height Anything drawn outside of that area is not visible When drawing shapes first position is at the top left corner Y <width-1, height-1> How to Draw on a Canvas Drawing Lines public void start(stage stage) { BorderPane window = new BorderPane(); Canvas canvas = new Canvas(150, 150); window.setcenter(canvas); GraphicsContext gc = canvas.getgraphicscontext2d(); gc.setfill(color.red); gc.setstroke(color.blue); gc.strokeoval(20, 20, 40, 40); gc.filloval(70, 20, 40, 40); gc.fillrect(20, 80, 40, 40); gc.strokerect(70, 80, 40, 40); Scene scene = new Scene(window, 150, 150); stage.setscene(scene); stage.show(); strokeline(leftx, lefty, rightx, righty) Change the thickness with setlinewidth gc.strokeline(0, 150, 150, 0); gc.setlinewidth(3); gc.setstroke(color.gold); for (int fromtop = 10; fromtop <= 150; fromtop += 10) { gc.strokeline(0, 0, 150, fromtop); Text Object, No Canvas Needed Color @Override public void start(stage stage) { stage.settitle("graphics in JavaFX"); Group root = new Group(); Scene scene = new Scene(root, 300, 100, Color.WHITE); Text text = new Text(20, scene.getheight() / 1.8, "Hello CSC 335!"); text.setfont(font.font("serif", FontWeight.EXTRA_BOLD, FontPosture.REGULAR, 40)); text.setfill(color.red); text.setfontsmoothingtype(fontsmoothingtype.lcd); text.setstroke(color.darkred); root.getchildren().add(text); The Color class is used to define and manage the color in which shapes are drawn Can set the color for stroke and fill with setfill(color) and setstroke(color) javafx.scene.paint.color has many, many colors from Color.ALICEBLUE to Color.YELLOWGREEN stage.setscene(scene); stage.show(); 5
Color Colors can also be defined with an RGB value (0-255), to set the relative contribution of the primary colors red, green, blue Color color = new Color.rgb(80, 210, 110); gc.setfill(color); gc.setstroke(color); gc.setlinewidth(4); // width set to 4 pixels gc.strokeoval(20, 20, 40, 40); gc.filloval(70, 20, 40, 40); Clear" the Canvas Consider a view that draws a circle from from 1 to SimpleModel.currentCount() @Override public void update(observable themodel, Object o) { SimpleModel model = (SimpleModel) themodel; gc.setfill(color.pink); gc.fillrect(0, 0, canvas.getwidth(), canvas.getheight()); gc.setfill(color.aqua); Clearing the Canvas Also a clearrect() method that fills the specified region with the current transparent (background) color class Image public Image(String url, boolean backgroundloading) Construct a new Image with the specified parameters. Parameters: url: the string representing the URL when fetching the pixel data backgroundloading = false which indicates build image fully before moving on, almost always want this. Image hunter = new Image("file:images/TheHunter.png", false); Image wumpus = new Image("file:images/wumpus.png", false); drawimage public void drawimage(image img, double x, double y) public void drawimage(image img, double x, double y, int width, int height) Draws an image at the given x, y position using the width and height of the given image. Parameters: img: the image to be drawn or null. x: the X coordinate of the upper left of image y: the Y coordinate on the upper left of image gc.drawimage(hunter, 50, 110); gc.drawimage(wumpus, 90, 70); 6