Unformatted Document Excerpt
Coursehero >>
Alabama >>
W. Alabama >>
SE 382
Course Hero has millions of student submitted documents similar to the one
below including study guides, practice problems, reference materials, practice exams, textbook help and tutor support.
Course Hero has millions of student submitted documents similar to the one
below including study guides, practice problems, reference materials, practice exams, textbook help and tutor support.
from
Java
Learning Excerpts to Program with Robots
Byron Weber Becker
University of Waterloo
For CS349 | SE 382 students at the University of Waterloo
Copyright 2005 by Thumbodys Thinking Inc. All rights reserved. Cover art by Joel Weber Becker. Copyright 2001. No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without the prior written permission of the author. Acknowledgements Portions of this text are adapted from Karel++: A Gentle Introduction to the Art of Object-Oriented Programming by Joseph Bergin, Mark Stehlik, Jim Roberts, and Richard Pattis, copyright 1997 by John Wiley & Sons, Inc. This material is used by permission of John Wiley & Sons, Inc. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Thumbodys Thinking Inc. is independent of Sun Microsystems, Inc. Published by Thumbodys Thinking Inc. 211 Simeon St. Kitchener, ON N2H 1S9 Canada (519) 888-4567 x4661 bwbecker@uwaterloo.ca Printed in Canada by Pandora Press Can 33 Kent Ave. Kitchener, Ontario N2G 3R2 ISBN 0-9733618-2-4 Printing History: August 2002: August 2003: February 2004: August 2004: April 2005: July 2005: Version 0.5 Version 0.6 Version 0.7 Version 0.75 Version 0.83 Version 0.90
644
Chapter 12 Polymorphism This can isolate the decision of which class to use to a single pointwhich constructor to call when the list is first created. If you change your mind, there is only one place to change and the entire program can take advantage of your new approach. For example, an inventory program might include a method to remove the items just sold from the items in stock, as sketched in the following code fragment. Note that List is used throughout, leaving lots of flexibility to use either ArrayList, LinkedList, or some other implementation of the List interface as the actual class.
1 public class Inventory extends Object 2 { private List inventory = new ArrayList(); 3 private List reorder = new LinkedList(); 4 ... 5 6 /** Remove the specified items from the current inventory. Update the list of items 7 * to reorder. 8 * @itemsSold The items that have been sold and need to be removed from inventory. */ 9 public void removeInventory(List itemsSold) 10 { for (int i=0; i<itemsSold.size(); i++) 11 { // Remove the item from the inventory. Object item = itemsSold.get(i); 12 13 this.inventory.remove(item); 14 15 // If its the last one and not already on the reorder list, add it if (!this.inventory.contains(item) && 16 17 !this.reorder.contains(item)) 18 { this.reorder.add(item); 19 } 20 } 21 } 22 }
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
By using List to declare variables in lines 2, 3, and 9, the programmer has left lots of flexibility to change the actual classes being used. For example, the ArrayList in line 2 could be changed to a LinkedList with no further changes in the rest of the program.
12.6 GUI: Layout Managers
Most graphical user interfaces allow users to interact with many components (buttons, textboxes, sliders, and so on). The issue to be addressed in this section is how Java arranges the components in a panel, both initially and as the user resizes the frame displaying the panel. The task of arranging the components on the panel is called layout. Java uses strategy objects called layout managers to determine how to arrange the components. By using strategy objects, JPanel can display the same set of components in many different arrangements.
Pattern
Strategy
The FlowLayout Strategy
The default layout strategy for a JPanel is an instance of FlowLayout. It adds components to the current row until there is no more room. It then starts a new
12.6 GUI: Layout Managers row. The length of a row is determined by the width of the JPanel. Wider panels will have more components on a row. The left image in Figure 12-18 shows four components organized with a flow layout strategy. The components are displayed left to right, top to bottom, in the same order they were added. The right image shows how those same components are reorganized when the frame is narrower. A FlowLayout object centers the row by default. It can also be set to align them on either the left or right side of the panel. Each component has a preferred size, which is respected by FlowLayout. As well soon see, some layout managers ignore such size information.
Figure 12-18: The FlowLayout strategy.
645
The GridLayout Strategy
The strategy implemented by a GridLayout object is to place all of the components into a grid, as shown in Figure 12-19. Each component is made the same size as all the others, completely ignoring their preferred sizes. The number of rows and columns is set when the strategy object is created.
Figure 12-19: The GridLayout strategy.
Setting a JPanels layout strategy is done with its setLayout method, as shown in lines 17-18 of Listing 12-19. This listing is already showing the program structure we will adopt for our graphical user interfaces. A group of components is combined by extending JPanel. Laying out the components is a distinct task that is delegated to a private helper method we will always call layoutView. Listing 12-20 displays an instance of this panel in a frame.
646
Chapter 12 Polymorphism
Listing 12-19: A JPanel extended to show a group of buttons, organized with a grid strategy. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import java.awt.*; import javax.swing.*; public class DemoGridLayout extends JPanel { private JButton one = new JButton("One"); private JButton two = new JButton("Two");
// Instance variables for the last four buttons are omitted.
public DemoGridLayout() { super(); this.layoutView(); } private void layoutView() { // Set the layout strategy to a grid with 2 rows and 3 columns. GridLayout strategy = new GridLayout(2, 3); this.setLayout(strategy);
// Add the components.
For use by CS349|SE382 Only
this.add(this.one); this.add(this.two);
// Code to add the last four buttons is omitted.
} }
Listing 12-20: A main method that displays a custom JPanel in a frame. 1 2 3 4 5 6 7 8 9 10 11 12 13 14
import javax.swing.*; public class GridLayoutMain { public static void main(String[] args) { JPanel p = new DemoGridLayout(); JFrame f = new JFrame("GridLayout"); f.setContentPane(p); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); // Base frame size on preferred size of components. f.setVisible(true); } }
University of Waterloo, Waterloo, Ontario
The BorderLayout Strategy
The BorderLayout strategy lays out up to five objects in a panel, as shown in Figure 12-20. No matter what size the panel is, the north and south areas cover the entire width. Their heights are determined by the preferred heights of the components they hold. The east and west areas expand or contract to occupy the remaining height of the panel. Their widths are determined by the preferred sizes of the components they hold. Finally, the center area expands or contracts to occupy the remaining space.
12.6 GUI: Layout Managers
647
Figure 12-20: The BorderLayout strategy.
Areas that do not have a component will not take any space. For example, if the button was left out of the east area in Figure 12-20, the center area would simply expand to fill it. The layout managers weve seen previously arrange the components according to the order in which they are added to the panel. BorderLayout handles positioning with a constraint specified when the component is added. The constraint says where the component should be placed. Listing 12-19 could be modified to use a BorderLayout strategy by changing line 17 to
17
BorderLayout strategy = new BorderLayout();
and changing the lines that add the components to use the required constraints.
21 22
this.add(this.one, BorderLayout.EAST); this.add(this.two, BorderLayout.NORTH);
Other Layout Strategies
The BoxLayout strategy arranges components in a horizontal row or a vertical column. It tries to respect the preferred sizes of components. However, if a component does not have a maximum size (such as a text field or text area), it will grow or shrink to fill available space. Like GridLayout, GridBagLayout uses a grid. But its cells can vary in size and a component can take up more than one cell in the grid. To accomplish all this, it uses a fairly complex constraint, called a GridBagConstraint. Another constraint-based layout strategy is SpringLayout. It works by specifying how the edges of each component relate to other components or to the edges of the enclosing panel.
Nesting Layout Strategies
A single layout strategy is usually not enough for a complex graphical user interface. Consider Figure 12-21, for example. None of the simpler layout strategies weve covered can handle this by themselves. GridBagLayout and SpringLayout
648
Chapter 12 Polymorphism could do it, but using them would involve a tremendous amount of work in setting all the constraints. An excellent solution is based on the fact that JPanel is also a component. It can be added to another JPanel that is organized by its own layout strategy object. The user interface in Figure 12-21 is organized with four JPanel objects using code like that shown in Listing 12-21. Notice that buttonsPanel (lines 29-40) is a method that returns a JPanel. This JPanel is then added as a component to another JPanel (line 25). The class HangmanView can be placed in a frame by substituting it for DemoGridLayout in Listing 12-20.
Figure 12-21: Laying out a complex user interface using nested layout strategies.
Looking Ahead Problem 12.12 asks you to finish implementing HangmanView.
hangman, a JPanel managed by BorderLayout. gallows, a custom component in the CENTER area of hangman.
For use by CS349|SE382 Only
phrase, a JLabel in the SOUTH area of hangman. buttons, a JPanel managed by BoxLayout that holds letters and controls. Positioned in the EAST area of hangman. letters, a JPanel managed by GridLayout that holds 26 JButtons.
University of Waterloo, Waterloo, Ontario
controls, a JPanel managed by GridLayout that holds 2 JButtons.
12.7 Patterns
Listing 12-21: Implementing nesting layout managers. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
649
import becker.xtras.hangman.*; import javax.swing.*; import java.awt.*;
/** Layout the view for the game of hangman. * * @author Byron Weber Becker */
public class HangmanView extends JPanel { // Constructor omitted.
/** Layout the view in a JPanel managed by BorderLayout. */
private void layoutView() { JPanel hangman = this; // Use same name as Figure 12-21 hangman.setLayout(new BorderLayout());
// South
Pattern
Strategy
JLabel phrase = new JLabel("GO FLY A KITE"); hangman.add(phrase, BorderLayout.SOUTH);
// Center
JComponent gallows = new GallowsView(new SampleHangman()); hangman.add(gallows, BorderLayout.CENTER);
// East -- controls
JPanel buttons = this.buttonsPanel(); hangman.add(buttons, BorderLayout.EAST); }
/** Layout and return a subpanel with all the buttons. */
private JPanel buttonsPanel() { // A JPanel holding 26 buttons, one for each letter of the alphabet. JPanel letters = new JPanel(); letters.setLayout(new GridLayout(13, 2)); for (char ch='A'; ch<='Z'; ch++) { letters.add(new JButton("" + ch)); }
// A JPanel holding the New Game and Forfeit buttons is omitted.
return letters; } }
12.7 Patterns
12.7.1 The Polymorphic Call Pattern
Name: Polymorphic Call Context: You are writing a program that handles several variations of the same
general idea (for example, several kinds of bank accounts). Each kind of thing has similar behaviors, but the details may differ.
13
Graphical User Interfaces
13
A graphical user interface (GUI) often gives us the first glimpse of a new program. The information it displays indicates the programs purpose, whereas a quick review of the interfaces controls and menus gives us a feel for what the program can do. Graphical user interfaces operate in a fundamentally different way from text-based interfaces. In a text-based interface the program is in control, demanding information when it suits the program rather than the user. With a graphical user interface, the user has much more control. Users can perform operations in their prefered order rather than according to the programs demands. Naturally, this difference will require a different way to structure the program. This chapter pulls together the graphical user interface thread running through each chapter and adds new material, enabling us to design and build graphical user interfaces for our programs.
Chapter Objectives
After studying this chapter, you should be able to: Write a graphical user interface using existing Java components Implement interfaces using the model-view-controller pattern Structure a graphical user interface using multiple views Write new components for use in graphical user interfaces
662
Chapter 13 Graphical User Interfaces
13.1 Overview
Building the graphical user interface (GUI) for a program can be one of the more rewarding parts of programming. Finally, we begin to see the results of our labor and are able to manipulate our program directly. The user interface is also a place where we can use artistic or esthetic skills and sensibilities. On the other hand, creating GUIs can also involve a lot of time and frustration. Developing them will call upon every skill weve learned so far: extending existing classes, writing methods, using collaborating classes and instance variables, using Java interfaces, and so on. However, following a concrete set of steps will make the job easier. Watch for patterns that occur repeatedly. Master those patterns, and youll be able to write GUIs like a professional. We will proceed by developing a variant of the game of Nim. The requirements are specified in Figure 13-1.
Figure 13-1: Requirements for the game of Nim.
For use by CS349|SE382 Only
A game of Nim begins with a pile of tokens. Two players take turns removing one, two, or three tokens from the pile. The last player to remove a token wins the game. The players will be designated red and black. The first one to move will be chosen randomly. The initial size of the pile is between ten and twenty tokens and is set randomly. An example of one possible user interface is shown on the right.
University of Waterloo, Waterloo, Ontario
13.1.1 Models, Views, and Controllers
Recall from Chapter 8 that graphical user interfaces are usually structured using the model-view-controller pattern. Figure 13-2, reproduced here from 8.6.2, shows the core ideas. The model is the part of the program that represents the problem at hand. In our game of Nim, its the model that will keep track of how many tokens remain on the pile, whose turn it is to move next, and who (if anyone) has won the game. The model also enforces rules. For example, it will not allow a player to take more than three tokens. The user interface is composed of the view and the controller. The user, represented by the eye and the mouse, uses the view to obtain information from the model. Its the view, for example, that displays the current size of the pile and whose turn it is. The user interacts with the controller to change the model. In the case of Nim, the controller is used to remove some tokens or to start a new game.
Key Idea The model maintains relevant information. The view displays it. The controller requests changes to it.
13.1 Overview
663
Figure 13-2: The view and controller interact with the user and the model.
User Interface View Model Co ntroller
The arrow between the controller and the view indicates that the controller will need to call methods in the view. The lack of an arrow going the other way indicates that the view will generally not need to call the controllers methods. The two arrows between the user interface and the model indicate the view and controller will both have reason to call the models methodsthe view to obtain information to display and the controller to tell the model how the user wants it to change. The dotted arrow from the model to the user interface indicates that the model will be very restrictive in how it calls methods in the interface. Essentially, it will call only a single method to tell the view that it has changed and the view needs to update the display. The interaction of the controller, model, and view may seem complicated at first. However, it follows a standard pattern, which includes the following typical steps, performed in the following order: The user manipulates the user interface; for example, enters text in a component. The user interface component notifies its controller by calling a method that we write. The controller calls a mutator method in the model, perhaps supplying additional information such as text that was entered in the component. Inside the mutator method, the model changes its state, as appropriate. Then it calls the views update method, informing the view that it needs to update the information it displays. Inside the update method, the view calls accessor methods in the model to gather the information it needs to display. It then displays that information. Our first graphical user interface will use a single view and controller. We will learn in Section 13.5, however, that using multiple views and controllers can actually make an interface easier to build. We will plan for that possibility from the beginning.
Key Idea Interfaces usually have more than one view.
664
Chapter 13 Graphical User Interfaces
13.1.2 Using a Pattern
Pattern
Model-View-Controller
Models, views, and controllers make up a pattern that occurs repeatedly. The steps for using this pattern are shown in Figure 13-3. Youll find that many of the steps are familiar from previous chapters in the book. None of this is truly new material. It just puts together what we have already learned in a specific way, resulting in a graphical user interface. We will elaborate upon these steps in each of the next three subsections.
Figure 13-3: Steps for building a graphical user interface.
Set up the Model and View 1. Write three nearly empty classes: a. The model, implementing becker.util.IModel. b. The view, extending JPanel and implementing becker.util.IView. The constructor takes an instance of the model as an argument. c. A class containing a main method to run the program. 2. In main, create instances of the model and the view. Display the view in a frame.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
Build and Test the Model 1. Design, implement and test the model. In particular, a. add commands used by the controllers to change the model. b. add queries used by the views to obtain the information to display. 2. Call updateAllViews just before exiting any method that changes the models state.
Build the View and Controllers 1. Design the interface. 2. Construct the required components and lay them out in the view. 3. Write updateView to update the information displayed by the view to reflect the model. 4. Write appropriate controllers for each of the components that update the model. Register the controllers.
13.2 Setting up the Model and View
The first step sets up the basic architecture for the model-view-controller pattern. This is where the connections between the classes are established and by the end of this step we will have a program that we can run, even though it wont do anything more than show us an empty frame. The class diagram of the resulting program is shown in Figure 13-4.
13.2.1 The Models Infrastructure
The models primary purpose is to model the problem, in our case the game of Nim. It must also inform the views each time the model changes (and therefore
13.2 Setting up the Model and View the view needs to change the information it displays). It is this update function that we are focusing on now.
Figure 13-4: A partial class diagram for Nim.
665
IModel
IView
NimModel
-ArrayList<IView> views other instance variables omitted +NimM odel( ) +void addView(IView view) +void removeView(IView view) +void updateAllViews( ) other methods omitted
NimView
-NimM odel model other instance variables omitted +NimView(NimM odel aM odel) +void updateView( ) other methods omitted
Nim
+void main(String[ ] args)
Its possible that a model may have several views, and we will provide for that possibility right away by keeping a list of views that we need to inform of changes. These requirements are embodied in the IModel interface. It specifies that a model needs to be able to add a view, remove a view, and update all views. The model will only need to call one method in the views, updateView. It expects each view to implement the IView interface. A class with this infrastructure is shown in Listing 13-1. Every model will start out just like this, except that the name of the class, the constructor, and the class documentation will change to reflect the programs purpose.
Looking Back ArrayLists were discussed in Section 8.5.1 and interfaces in Section 7.6. Key Idea The IModel interface specifies methods needed in the model to manage views.
666
Chapter 13 Graphical User Interfaces
Listing 13-1: The models class with infrastructure to inform views of changes.
Find The Code ch13/nimInfrastructure/
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import becker.util.IModel; import becker.util.IView; import java.util.ArrayList;
/** A class implementing a version of "Nim." There is a (virtual) pile of tokens. Two * players take turns removing 1, 2 or 3 tokens. The player who takes the last token * wins the game. * * @author Byron Weber Becker */
public class NimModel extends Object implements IModel { private ArrayList<IView> views = new ArrayList<IView>();
/** Construct a new instance of the game of Nim. */
public NimModel() { super(); }
/** Add a view to display information about this model. * @param view The view to add. */
public void addView(IView view) { this.views.add(view); }
/** Remove a view that has been displaying information about this model. * @param view The view to remove. */
public void removeView(IView view) { this.views.remove(view); }
/** Inform all the views currently displaying information about this model that the * model has changed and their display may need changing too. */
public void updateAllViews() { for (IView view : this.views) { view.updateView(); } } }
Of course, more must be added to NimModel. In particular, it does nothing yet to model the game of Nim. But when one of the players takes some tokens from the pile, for example, we now have the infrastructure in place to inform all of the views that they need to update the information they are showing the players.
Using AbstractModel
These three methods are always required to implement a model. Instead of writing them each time we create a model class, we can put them in their own class. Our model can simply extend that class. Such a class, AbstractModel, is in the becker.util package. Its code is almost exactly like the code in Listing 13-1 except for the name of the class. NimModel is then implemented as follows:
13.2 Setting up the Model and View
import becker.util.AbstractModel; public class NimModel extends AbstractModel { public NimModel() { super(); }
// Other methods will be added here to implement the model.
667
} AbstractModel implements IModel, implying that NimModel also implements that interface. The clause implements IModel does not need to be repeated. The Java library has a class named Observable that is very similar to AbstractModel. It is designed to work with an interface named Observer that is very similar to IView. Why dont we use them instead? There are two reasons. First, the update method in Observable is more complex than we need. Second, and more importantly, the Java library doesnt have an interface corresponding to IModel. Therefore, the model must always extend Observable. Sometimes this isnt a problem (as with NimModel). But other times the model must extend another class. In those situations, the missing interface is required and these classes cant be used. At the time of this writing, Java library contains 6,558 classes. A number of those classes define their own versions of Observer and Observable, as we have done. Its interesting to note that none of the classes use Observer and Observable.
13.2.2 The Views Infrastructure
Each view will be a subclass of JPanel1 that contains the user interface components required to interact with the model. But for now we will provide only the infrastructure for updating the view. That consists of implementing the IView interface, which specifies the updateView method called by the model in updateAllViews. This is all shown in Listing 13-2. The view is passed an instance of the model when it is constructed. The model is saved in an instance variable and the view adds itself to the models list of views. Finally, the view must update the information it displays by calling updateView in line 16.
Key Idea A component is nothing more than an object designed for user interfaces. Buttons, scroll bars, and text fields are all examples of components.
1
This is true most of the time. Its convenient for menus to extend JMenuBar and toolbars to extend JToolBar.
668
Chapter 13 Graphical User Interfaces
Listing 13-2: The views class set up to receive notification of changes in the model.
Find The Code ch13/nimInfrastructure/
For use by CS349|SE382 Only
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
import javax.swing.JPanel; import becker.util.IView;
/** Provide a view of the game of Nim to a user. * * @author Byron Weber Becker */
public class NimView extends JPanel implements IView { private NimModel model;
/** Construct the view. * @param aModel The model we will be displaying. */
public NimView(NimModel aModel) { super(); this.model = aModel; this.model.addView(this); this.updateView(); }
/** Called by the model when it changes. Update the information this view displays. */
public void updateView() { } }
13.2.3 The
main Method
The last step in setting up the infrastructure is to write the main method. It constructs an instance of the model and an instance of the view. It then displays the view in an appropriately sized frame. This is shown in Listing 13-3.
Listing 13-3: The main method for running the program. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
University of Waterloo, Waterloo, Ontario
Find The Code ch13/nimInfrastructure/
import javax.swing.JFrame;
/** Run the game of "Nim." There is a (virtual) pile of tokens. Two players take turns * removing 1, 2 or 3 tokens. The player who takes the last token wins the game. * * @author Byron Weber Becker */
public class Nim extends Object { public static void main(String[] args) { NimModel model = new NimModel(); NimView view = new NimView(model); JFrame f = new JFrame("Nim"); f.setSize(250, 200); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setContentPane(view); f.setVisible(true); } }
13.3 Building the Model
669
13.3 Building the Model
Figure 13-3 describes the steps for building a user interface. It suggests that the model requires commands to change its state and queries for the views to use in updating the display. If we keep this in mind while using the development process discussed in Chapter 11, we will discover that the model for Nim needs the following methods: removeTokens, a command to remove one, two, or three tokens from the pile getPileSize, a query returning the current size of the pile getWhoseTurn, a query returning whose turn it is getWinner, a query returning which player, if any, has won the game The requirements in Figure 13-1 specify that the first player and the initial size of the pile are chosen randomly. The default constructor will do that, but randomness makes the class hard to test so well also add a private constructor allowing our test harness to easily specify the pile size and first player. Representing the two players is a perfect job for an enumeration type. We will use three values: one for the red player, one for the black player, and one for nobody. The last one might be used, for example, as the answer to the query of who has won the game (if the game isnt over yet, nobody has won). The Player enumeration is shown in Listing 13-4 and the NimModel class is shown in Listing 13-5. In NimModel, the only method (other than the constructors) that changes the models state is removeTokens. After it has made its changes it calls updateAllViews at line 96 to inform the views that they should update the information they display.
Listing 13-4: The Player enumeration type. 1 2 3 4 5 6 7 /** The players in the game of Nim, plus NOBODY to indicate situations where * neither player is applicable (for example, when no one has won the game yet). * * @author Byron Weber Becker */ Find The Code ch13/nimOneView/
Looking Back Enumerations were discussed in Section 7.3.4.
Key Idea Call updateAllViews before returning from a method that changes the model.
public enum Player { RED, BLACK, NOBODY }
670
Chapter 13 Graphical User Interfaces
Listing 13-5: The completed NimModel class.
Find The Code ch13/nimOneView/
1 import becker.util.AbstractModel; 2 import becker.util.Test; 3 4 /** A class implementing a version of "Nim." There is a (virtual) pile of tokens. Two 5 * players take turns removing 1, 2 or 3 tokens. The player who takes the last token 6 * wins the game. 7 * 8 * @author Byron Weber Becker */ 9 public class NimModel extends AbstractModel 10 { // Extending AbstractModel is an easy way to implement the IModel interface. 11 12 // limit randomly generated pile sizes and how many tokens can be removed at once 13 public static final int MIN_PILESIZE = 10; 14 public static final int MAX_PILESIZE = 20; 15 public static final int MAX_REMOVE = 3; 16 private int pileSize; 17 18 private Player whoseTurn; 19 private Player winner = Player.NOBODY; 20 21 /** Construct a new instance of the game of Nim. */ 22 public NimModel() 23 { // call the other constructor to do the initialization this(NimModel.random(MIN_PILESIZE, MAX_PILESIZE), 24 25 NimModel.chooseRandomPlayer()); 26 } 27 28 /** We need a way to create a non-random game for testing purposes. */ 29 private NimModel(int pileSize, Player next) 30 { super(); 31 this.pileSize = pileSize; 32 this.whoseTurn = next; 33 } 34 35 /** Generate a random number between two bounds. */ 36 private static int random(int lower, int upper) 37 { return (int)(Math.random()*(upper-lower+1)) + lower; 38 } 39 /** Choose a player at random. 40 41 * @return Player.RED or Player.BLACK with 50% probability for each */ 42 private static Player chooseRandomPlayer() 43 { if (Math.random() < 0.5) 44 { return Player.RED; 45 } else 46 { return Player.BLACK; 47 } 48 } 49 50 /** Get the current size of the pile. 51 * @return the current size of the pile */ 52 public int getPileSize() 53 { return this.pileSize; 54 } continued...
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.3 Building the Model
Listing 13-5 continued 55 56 /** Get the next player to move. 57 * @return Either Player.RED or Player.BLACK if the game has not yet been won, 58 * or Player.NOBODY if the game has been won. */ 59 public Player getWhoseTurn() 60 { return this.whoseTurn; 61 } 62 63 /** Get the winner of the game. 64 * @return Either Player.RED or Player.BLACK if the game has already been won; 65 * Player.NOBODY if the game is still in progress. */ 66 public Player getWinner() 67 { return this.winner; 68 } 69 70 /** Is the game over? 71 * @return true if the game is over; false otherwise. */ 72 private boolean gameOver() 73 { return this.pileSize == 0; 74 } 75 76 /** Remove one, two or three tokens from the pile. Ignore any attempts to take 77 * too many or too few tokens. Otherwise, remove howMany tokens from the pile 78 * and update whose turn is next. 79 * @param howMany How many tokens to remove. 80 * @throws IllegalStateException if the game has already been won */ 81 public void removeTokens(int howMany) 82 { if (this.gameOver()) 83 { throw new IllegalStateException( 84 "The game has already been won."); 85 } 86 87 if (this.isLegalMove(howMany)) 88 { this.pileSize = this.pileSize - howMany; 89 if (this.gameOver()) 90 { this.winner = this.whoseTurn; 91 this.whoseTurn = Player.NOBODY; 92 } else 93 { this.whoseTurn = 94 NimModel.otherPlayer(this.whoseTurn); 95 } 96 this.updateAllViews(); 97 } 98 } 99 100 // Is howMany a legal number of tokens to take? private boolean isLegalMove(int howMany) 101 102 { return howMany >= 1 && howMany <= MAX_REMOVE && 103 howMany <= this.pileSize; 104 } 105 continued...
671
672
Chapter 13 Graphical User Interfaces
Listing 13-5 continued 106 107 108 109 110 111 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 } // Return the other player.
private static Player otherPlayer(Player who) { if (who == Player.RED) { return Player.BLACK; } else if (who == Player.BLACK) { return Player.RED; } else { throw new IllegalArgumentException(); } }
// The addView, removeView, and updateAllViews methods could be included // here. That isnt necessary in this case because NimModel extends AbstractModel. /** Test the class. */
public static void main(String[] args) { System.out.println("Testing NimModel"); NimModel nim = new NimModel(10, Player.RED); Test.ckEquals("pilesize", 10, nim.getPileSize()); Test.ckEquals("winner", Player.NOBODY, nim.getWinner()); Test.ckEquals("next", Player.RED, nim.getWhoseTurn());
/* ------------ find the code to see complete test suite ------------*/
For use by CS349|SE382 Only
}
13.4 Building the View and Controllers
The view, of course, is what displays information from the model to the user. It is the visible part of the user interface. The controllers are what make the interface interactive. They listen for the user manipulating controls such as buttons or menus and then make appropriate calls to the commands in the model.
University of Waterloo, Waterloo, Ontario
13.4.1 Designing the Interface
Java comes with many user interface components including buttons, text fields, menus, sliders, labels, and so on. Some of these are shown in Figure 13-5. Designing an interface includes deciding which of these components are most appropriate to display the model and to accept input from the user, and how to best arrange them on the screen. For now, while were learning the basics, we will restrict ourselves to labels for displaying information and text fields to accept input from the user. In Section 13.7 we will explore other components.
Key Idea The program shown in Figure 13-5 contains lots of code to help get you started using components.
13.4 Building the View and Controllers
673
Figure 13-5: An application demonstrating many of the components available for constructing views. The code is available in the examples download.
Find The Code ch13/componentDemo/
Our first view will appear as shown in Figure 13-6. It shows the end of the game after Red has won. The text areas (one has 2 in it, the other has 3) are enabled when its the appropriate players turn and disabled when it isnt. When the game is over both are disabled, as shown here.
Figure 13-6: The first view for the game of Nim.
674
Chapter 13 Graphical User Interfaces
13.4.2 Laying Out the Components
The components for any view can be divided into those that require ongoing access and those that dont. In this view, the following five components require ongoing access to change the information they display or to obtain changes made by the user. Two JTextFields to accept input from the players One JLabel showing the piles current size Two JLabels announcing the winner (they are not visible until there is a winner, and even then only one is shown) References to these objects will be stored in instance variables.
// get how many tokens to remove
Key Idea References to components requiring ongoing access are stored in instance variables.
private JTextField redRemoves = new JTextField(5); private JTextField blackRemoves = new JTextField(5);
// info to display
private JLabel pileSize = new JLabel(); private JLabel redWins = new JLabel("Winner!"); private JLabel blackWins = new JLabel("Winner!");
Looking Back Layout managers were discussed in Section 12.6.
For use by CS349|SE382 Only
The components that do not require ongoing access include several JPanel objects used to organize the components and the borders around them. Instance variables storing references to these components are not required. These components are laid out using four nested JPanels, as shown in Figure 13-7.
Figure 13-7: NimView uses nested JPanels to lay out the components.
blackRemoves is a JTextField. blackWins is a JLabel to announce
University of Waterloo, Waterloo, Ontario
when black wins (usually not visible).
2
3
Winner!
Winner!
black is a JPanel to group blackRemoves and blackWins. center is a JPanel to group the pSize is a JPanel holding the label displaying the pile's current size. The entire view is also a JPanel, organized with a BorderLayout.
panel for black and the panel for red.
The task of laying out the components occurs when the view is constructed and is usually complex enough to merit a helper method called from the constructor. Well call the helper method layoutView, as shown in Listing 13-6. The method carries out the following tasks: The first JPanel, named red, is defined in lines 12-15. It contains a JTextField to accept information from the red player and a label to an-
13.4 Building the View and Controllers nounce if red is the winner. The JPanel itself is wrapped in line 15 with a border to label it. The second JPanel, named black, is just like red except that it contains components for the black player. The third JPanel, pSize, contains the label used to display the size of the pile. It, too, has a border to label it. The fourth JPanel, center, is not directly visible in the user interface. It exists solely to group the red and black JPanels into a single component that can be placed as a whole. Finally, recall that NimView is itself a JPanel that can have its own layout manager. It is set in line 36 to be a BorderLayout. Only two of the layouts five areas are used, the center and the south side. The center section grows and shrinks as its container is resized. Thats where we put the center panel containing red and black. The south area contains pSize. Adding the layoutView method to NimView, as shown in Listing 13-6, and running the program results in something that looks much like Figure 13-6. The pile size wont be displayed and both players will be declared winners. To display that information correctly we need to update the view with information from the model.
675
676
Chapter 13 Graphical User Interfaces
Listing 13-6: A helper method to lay out the view for Nim.
Find The Code ch13/nimOneView/
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
1 public class NimView extends JPanel implements IView 2 { // Instance variables omitted. 3 4 public NimView(NimModel aModel) 5 { // Details omitted. 6 this.layoutView(); 7 } 8 9 // Layout the view 10 private void layoutView() 11 { // A panel for the red player. JPanel red = new JPanel(); 12 13 red.add(this.redRemoves); 14 red.add(this.redWins); 15 red.setBorder(BorderFactory.createTitledBorder("Red")); 16 17 // A panel for the black player. JPanel black = new JPanel(); 18 19 black.add(this.blackRemoves); 20 black.add(this.blackWins); 21 black.setBorder(BorderFactory.createTitledBorder("Black")); 22 23 // Pilesize information. JPanel pSize = new JPanel(); 24 25 pSize.add(this.pileSize); 26 pSize.setBorder( 27 BorderFactory.createTitledBorder("Pile Size")); 28 29 // Group the red and black panels. JPanel center = new JPanel(); 30 31 center.setLayout(new GridLayout(1, 2)); 32 center.add(red); 33 center.add(black); 34 35 // Lay out the pieces in this view. this.setLayout(new BorderLayout()); 36 37 this.add(center, BorderLayout.CENTER); 38 this.add(pSize, BorderLayout.SOUTH); 39 } 40 }
13.4.3 Updating the View
The updateView method was already added when we set up the model and view architecture, but it doesnt do anything yet. It is called by the model each time the model changes so that it can update the views components with current information. For the moment, we want updateView to perform three basic tasks: Display the correct pile size. Enable the JTextField for the red player when it is the red players turn and disable it otherwise, with similar behavior for the black players text
Key Idea The updateView method is responsible for updating the view with the latest information from the model.
13.4 Building the View and Controllers field. When a component is disabled, the players cant use it, thus forcing each player to take his or her turn at the right time. Make redWins visible when the red player wins the game and invisible when it hasnt, with similar behavior for blackWins. Recall that the constructor received a reference to the model as a parameter. This reference was stored in an instance variable named, appropriately, model. We will use it to retrieve the necessary information from the model to carry out these tasks.
677
Updating the Size of the Pile
The component to display the size of the pile is a JLabel. It has a method, setText, which takes a string and causes the label to display it. Thus we can update the pile size display with the following statement:
this.pileSize.setText("" + this.model.getPileSize());
The result from getPileSize is an int. Adding it to the empty string forces Java to convert it to a string, which is what setText requires. If you run the program now, the user interface should show the pile size.
Updating the Text Fields
redRemoves
is the name of the text field used by the red player to say how many tokens to remove. To enable or disable it well use the setEnabled method, passing true to enable the component and false to disable it. We want the text field enabled when the following Boolean expression is true:
this.model.getWhoseTurn() == Player.RED
If this expression is false (its not reds turn), the component should be disabled. Thus
this.redRemoves.setEnabled( this.model.getWhoseTurn() == Player.RED);
enables redRemoves when its the red players turn and disables it otherwise. Recall that when the game is over, getWhoseTurn returns Player.NOBODY, resulting in both textfields being disabled.
Updating the Winners
When the game is over, we want either redWins or blackWins to become visible. If the game isnt over we want both to be invisible. Every component has a method named setVisible that makes the component visible when passed the value true and invisible when passed false. We can again use a simple Boolean expression to pass the correct value:
678
Chapter 13 Graphical User Interfaces
this.redWins.setVisible( this.model.getWinner() == Player.RED);
Looking Ahead We will refine updateView in Section 13.4.5.
A similar statement for blackWins completes the method. Like getWhoseTurn, getWinner can also return Player.NOBODY. The entire method is shown in Listing 13-7. If you run the program with this method completed, the user interface should display the initial pile size, one of the text fields should be enabled (indicating who removes the first tokens), and neither player should have their Winner label showing. However, the game still cant be played because the components will not yet respond to the users.
Listing 13-7: Updating the view with current information from the model. 1 public class NimView extends JPanel implements IView 2 { private NimModel model; 3 private JTextField redRemoves = new JTextField(5); 4 // Other instance variables, constructor, and methods omitted. 5 6 /** Called by the model when it changes. Update the information this view displays. */ public void updateView() 7 8 { // Update the size of the pile. this.pileSize.setText("" + this.model.getPileSize()); 9 10 11 // Enable and disable the text fields for each player. this.redRemoves.setEnabled( 12 13 this.model.getWhoseTurn() == Player.RED); 14 this.blackRemoves.setEnabled( 15 this.model.getWhoseTurn() == Player.BLACK); 16 17 // Proclaim the winner, if there is one. this.redWins.setVisible( 18 19 this.model.getWinner() == Player.RED); 20 this.blackWins.setVisible( 21 this.model.getWinner() == Player.BLACK); 22 } 23 }
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.4.4 Writing and Registering Controllers
The fundamental job of a controller is to detect when a user is manipulating a component and to respond in a way appropriate for this specific program. To best understand how this happens, we need to delve into a simplified version of a component. All of the Java components work similarly.
Understanding Events
For concreteness, lets consider JTextField. A simplified version appears in Listing 13-8. The key feature is the handleEvent method. It detects various kinds of events caused by the user such as pressing the Enter key or using the Tab key to either move in to or out of the text field. Listing 13-8 uses pseudocode for detecting these actions because we dont really need to know how they are accomplished.
13.4 Building the View and Controllers Thanks to encapsulation and information hiding, we can use the class without knowing those intimate details. What is important is that when one of these events occurs, two things happen. First, the component constructs an event object describing the event and containing information such as when the event occurred, if any keys were pressed at the time, which component created it, and so on. Second, the component calls a specific method, passing the event object as an argument. This method is one that we write as part of our controller. Its in this method that we have an opportunity to take actions specific to our program, such as calling the removeTokens method in the model.
Listing 13-8: A simplified version of JTextField. 1 public class JTextField extends ... 2 { private ActionListener actionListener; 3 private FocusListener focusListener; 4 5 public void addActionListener(ActionListener aListener) 6 { this.actionListener = aListener; 7 } 8 9 public void addFocusListener(FocusListener fListener) 10 { this.focusListener = fListener; 11 } 12 13 private void handleEvent() 14 15 16 17 18 19 20 21 22 23 24 25 26 }
679
{ if (user hit the Enter key) { construct an object, event, describing what happened this.actionListener.actionPerformed(event); } else if (user tabbed out of this text field) { construct an object, event, describing what happened this.focusListener.focusLost(event); } else if (user tabbed into this text field) { construct an object, event, describing what happened this.focusListener.focusGained(event); } else ... }
Obviously, the method called has a name. That means that our controller must have a method with the same name. Ensuring that it does is a perfect job for a Java interface. The names ActionListener and FocusListener at lines 2, 3, 5, and 9 in Listing 13-8 are, in fact, the names of Java interfaces. Our controllers will always implement at least one interface whose name ends with Listener. There are, unfortunately, two competing terminologies. Controller is a wellestablished name for the part of a user interface that interprets events and calls the appropriate commands in the model. Java uses the term listener for a class that is called when an event occurs. Most of the time the two terms mean the same thing.
Key Idea In Java, controllers implement methods defined in interfaces with names ending in Listener. Key Idea In Java, we use listener interfaces to implement controllers.
680
Chapter 13 Graphical User Interfaces
Implementing a Controller
When the user presses the Enter key inside a JTextField component, the component calls a method named actionPerformed. This method is defined in the ActionListener interface (and is, in fact, the only method defined there). It takes a single argument of type ActionEvent. Therefore, the skeleton for our controller class will be:
import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class RemovesController extends Object implements ActionListener { public void actionPerformed(ActionEvent e) { } }
Looking Ahead Implementing controllers can use a number of shortcuts. Some of them will be explored in Section 13.6, Controller Variations.
For use by CS349|SE382 Only
Inside actionPerformed we need to obtain the value the user typed into the text field and then call the model with that value. One approach is to have instance variables storing references to the text field and the model for the game. Then actionPerformed can be written as
public void actionPerformed(ActionEvent e) { String enteredText = this.textfield.getText(); int remove = convert enteredText to an integer; this.model.removeTokens(remove); }
University of Waterloo, Waterloo, Ontario
The conversion from a string to an integer can be done with parseInt, a static method in the Integer class. It will throw a NumberFormatException if the user enters text that is not a valid integer. If this exception is thrown, well recover in the catch clause by selecting the entered text and ignoring what was entered. The full method is shown in lines 21-29 of Listing 13-9. The rest of the listing, lines 11-19, is simply declaring the instance variables needed and initializing them in a constructor.
13.4 Building the View and Controllers
Listing 13-9: A controller for a text field. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
681
import javax.swing.JTextField; import java.awt.event.*;
/** A controller for the game of Nim that informs the model how many tokens a player * wants to remove. * * @author Byron Weber Becker */
public class RemovesController extends Object implements ActionListener { private NimModel model; private JTextField textfield; public RemovesController(NimModel aModel, JTextField aTextfield) { super(); this.model = aModel; this.textfield = aTextfield; } public void actionPerformed(ActionEvent e) { try { int remove = Integer.parseInt(this.textfield.getText()); this.model.removeTokens(remove); } catch (NumberFormatException ex) { this.textfield.selectAll(); } } }
Registering Controllers
The very last step to make this user interface interactive is to construct the controllers and register them with the text fields. Recall that the simplified version of JTextField shown in Listing 13-8 contained methods such as addActionListener and addFocusListener. They each took an instance of the similarly named interface and saved it in an instance variable. Registering our controller simply means calling the appropriate addXxxListener method for the relevant component, passing an instance of the controller as an argument. Weve only written one controller class, but well use one instance of it for the redRemoves text field and a second instance for the blackRemoves text field. A user interface often has several controllers, so it makes sense to have a helper method, registerControllers, just for constructing and registering controllers. It is called from the views constructor. The code in Listing 13-10 registers the red controller in two steps but combines the steps for the black controller.
Key Idea A common mistake is to write a controller but forget to register it.
682
Chapter 13 Graphical User Interfaces
Listing 13-10: A method registering the controllers with the appropriate components. 1 public class NimView extends JPanel implements IView 2 { // Instance variables omitted. 3 4 public NimView() 5 { // Some details omitted. 6 this.registerControllers(); 7 } 8 9 /** Register controllers for the components the user can manipulate. */ 10 private void registerControllers() 11 { RemoveController redController = 12 new RemoveController(this.model, this.redRemoves); 13 this.redRemoves.addActionListener(redController); 14 15 this.blackRemoves.addActionListener( 16 new RemoveController(this.model, this.blackRemoves)); 17 } 18 }
For use by CS349|SE382 Only
If you run the program with these additions, you should be able to play a complete, legal game, as shown in Figure 13-8.
University of Waterloo, Waterloo, Ontario
13.4 Building the View and Controllers
683
Figure 13-8: The user interface as it appears at each stage of a complete game.
a) The game begins with a pile of 10. Red has the first turn.
b) Red takes two tokens; now its blacks turn. The player must click in its text field before entering a value.
c) Black takes three tokens. Its reds turn. The 2 from the previous turn still shows. Red does not need to click in its text field before entering a value but must delete the old value before entering a new one.
d) Red takes one token.
e) Black takes two tokens, setting up red for a win.
f)
Red takes two tokens and is proclaimed the winner.
13.4.5 Refining the View
The program runs, as shown in Figure 13-8. However, there are three areas in which improvements could be made. The black user must click in its text field before entering a value. It would be nice if the player could simply type a new value. The value previously entered by a player remains in the text field and must be removed before entering a new value. Finally, the fonts used in the text fields and the JLabels are too small, given their importance in the user interface.
Focus
In any given user interface, at most one component will receive input from the users keyboard. This component is said to have the keyboard focus. Usually a com-
684
Chapter 13 Graphical User Interfaces ponent will give some visible sign when it has the focus. A component that accepts text will show a flashing bar called the insertion point. A button that has focus will often have a subtle box around the buttons label. Focus normally shifts from one component to the next in the order that they were added to their container. In the case of Nim, however, the component that should have the focus depends on whose turn it is. So, in the updateView method we can also update which component has the focus with the following code. It also replaces the previously entered value with an empty string.
if (this.model.getWhoseTurn() == Player.RED) { this.redRemoves.requestFocusInWindow(); this.redRemoves.setText(""); } else if (this.model.getWhoseTurn() == Player.BLACK) { this.blackRemoves.requestFocusInWindow(); this.blackRemoves.setText(""); }
FocusListener
For use by CS349|SE382 Only
Another approach is to write a controller class implementing the interface. It can detect when a component gains or loses focus. This is useful, for example, if action needs to be taken when a user moves in to or out of a component using either the mouse or the keyboard.
Fonts
A larger font for the various components can be specified with the setFont method. Its argument is a Font object describing the desired font. The following code could be included in the layoutView method to change the font for the five components.
// enlarge the fonts
University of Waterloo, Waterloo, Ontario
Font font = new Font("Serif", Font.PLAIN, 24); this.redRemoves.setFont(font); this.blackRemoves.setFont(font); this.redWins.setFont(font); this.blackWins.setFont(font); this.pileSize.setFont(font);
The first argument to the Font constructor specifies to use a font with serifs. Such fonts have short lines at the ends of the main strokes of each letter. Common fonts that have serifs include Times New Roman, Bookman, and Palatino. The string SansSerif can be used to specify a font without serifs. Helvetica is a common sans serif font. The string monospaced indicates a font using a fixed width for each letter. An example is Courier. You can also specify an actual font name like Helvetica as the first argument. However, you cant be assured that the font is actually installed on the computer unless you check. The program in Listing 13-11 will list all the names of all the fonts that are installed. Try it for yourself to see which fonts are installed on your computer.
13.4 Building the View and Controllers
Listing 13-11: A program to list the names of font installed on a computer. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
685
import java.awt.Font; import java.awt.GraphicsEnvironment;
/** List the font names available on the current computer system. * * @author Byron Weber Becker */
public class ListFonts extends Object { public static void main(String[] args) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Font[] names = ge.getAllFonts(); for (Font f : names) { System.out.println(f.getName()); } } }
The second argument for the Font constructor is the style. There are three basic styles, defined as constants in the Font class: PLAIN, ITALIC, and BOLD. ITALIC makes the letters slant and BOLD makes the strokes thicker. A bold, italic font can also be specified by adding the BOLD and ITALIC constants together and passing the result to the constructor. The third argument to the Font constructor is the fonts size. The size is measured in points where one point is 1/72nd of an inch. Ten to 12 points is a comfortable size for reading; use 16 points or larger for labels and headlines. This finishes our first view. The complete code is shown in Listing 13-12. Most components have many other ways to refine the way they look. Investigating them further falls outside the scope of this book. Exploring the documentation and method names for the component, as well as its superclasses, will often indicate what can be done.
686
Chapter 13 Graphical User Interfaces
Listing 13-12: The completed code for the NimView class. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
import import import import import import import import
javax.swing.JPanel; becker.util.IView; javax.swing.JTextField; javax.swing.JLabel; javax.swing.BorderFactory; java.awt.GridLayout; java.awt.BorderLayout; java.awt.Font;
/** Provide a view of the game of Nim to a user. * * @author Byron Weber Becker */
public class NimView extends JPanel implements IView { // The model implementing Nims logic. private NimModel model;
// Get how many tokens to remove.
private JTextField redRemoves = new JTextField(5); private JTextField blackRemoves = new JTextField(5);
// Info to display.
For use by CS349|SE382 Only
private JLabel pileSize = new JLabel(); private JLabel redWins = new JLabel("Winner!"); private JLabel blackWins = new JLabel("Winner!");
/** Construct the view. * @param aModel The model this view displays. */
public NimView(NimModel aModel) { super(); this.model = aModel; this.layoutView(); this.registerControllers(); this.model.addView(this); this.updateView(); }
/** Called by the model when it changes. Update the information thiis view displays. */
University of Waterloo, Waterloo, Ontario
public void updateView() { this.pileSize.setText("" + this.model.getPileSize()); this.redRemoves.setEnabled( this.model.getWhoseTurn() this.blackRemoves.setEnabled( this.model.getWhoseTurn() this.redWins.setVisible( this.model.getWinner() == this.blackWins.setVisible( this.model.getWinner() == == Player.RED); == Player.BLACK); Player.RED); Player.BLACK);
if (this.model.getWhoseTurn() == Player.RED) { this.redRemoves.requestFocusInWindow(); this.redRemoves.setText(""); } else if (this.model.getWhoseTurn() == Player.BLACK)
13.4 Building the View and Controllers
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 }
687
{ this.blackRemoves.requestFocusInWindow(); this.blackRemoves.setText(""); } }
/** Layout the view. */
private void layoutView() { // A panel for the red player JPanel red = new JPanel(); red.add(this.redRemoves); red.add(this.redWins); red.setBorder(BorderFactory.createTitledBorder("Red"));
// A panel for the black player
JPanel black = new JPanel(); black.add(this.blackRemoves); black.add(this.blackWins); black.setBorder(BorderFactory.createTitledBorder("Black"));
// Pilesize info.
JPanel pSize = new JPanel(); pSize.add(this.pileSize); pSize.setBorder( BorderFactory.createTitledBorder("Pile Size"));
// Group the red and black panels.
JPanel center = new JPanel(); center.setLayout(new GridLayout(1, 2)); center.add(red); center.add(black);
// Lay out the pieces in this view.
this.setLayout(new BorderLayout()); this.add(center, BorderLayout.CENTER); this.add(pSize, BorderLayout.SOUTH);
// Enlarge the fonts.
Font font = new Font("Serif", Font.PLAIN, 24); this.redRemoves.setFont(font); this.blackRemoves.setFont(font); this.redWins.setFont(font); this.blackWins.setFont(font); this.pileSize.setFont(font); }
/** Register controllers for the components the user can manipulate. */
private void registerControllers() { this.redRemoves.addActionListener( new RemovesController(this.model, this.redRemoves)); this.blackRemoves.addActionListener( new RemovesController(this.model, this.blackRemoves)); }
688
Chapter 13 Graphical User Interfaces
13.4.6 View Pattern
Views can be complex. However, they follow a common pattern, shown in Listing 13-13, which makes them much easier to understand and implement.
Listing 13-13: A pattern template for a view. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
import becker.util.IView; import javax.swing.JPanel; list of other imports public class viewName extends JPanel implements IView { private modelClassName model; component declarations public viewName(modelClassName aModel) { super(); this.model = aModel; this.layoutView(); this.registerControllers(); this.model.addView(this); this.updateView(); } public void updateView() { statements to update the components in the view } private void layoutView() { statements to lay out the components within the view } private void registerControllers() { statements to construct and register controllers } }
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.5 Using Multiple Views
Now lets implement a different user interface for the same game. Because the NimModel class exhibits very low coupling with its first view (calling only the updateView method via the IView interface), we will be able to replace the user interface without changing NimModel at all. Our new interface is illustrated in Figure 13-9. Instead of typing in the number of tokens to remove, the user clicks the appropriate button. Like our previous interface, components are disabled when they dont apply. For example, the black players buttons are shown disabled and when there are only 2 tokens remaining on the pile, the Remove 3 Tokens button will be disabled for both players. Like our previous interface, Winner! is displayed for the winning player at the appropriate time.
Key Idea One of the strengths of the ModelView-Controller pattern is the low coupling between the various parts.
13.5 Using Multiple Views
689
Figure 13-9: A different user interface for Nim.
We could write this user interface as one big view, as we did previously. However, this view has a total of nine components to manage, raising the overall complexity. Furthermore, the four components for the red player are managed almost exactly like those for the black player. This suggests that some good abstractions might simplify the problem. Recall that we wrote the model anticipating multiple views. The model has a list of views and each time the models state changes, it goes through list that and tells each view to update itself. This allows us to decompose the overall view into a number of sub-views. Each sub-view will add itself to the models list of views and will have its updateView method called at the appropriate times. This version of the interface will use three sub-views: one for the red player, one for the black player, and one to display the pile size. NimView will still exist to organize the three sub-views. Dividing the view into several sub-views has two distinct advantages. First, each view can focus on a smaller part of the overall job, allowing it to be simpler, easier to understand, easier to write, and easier to debug. Second, sub-views can be easily changed or even replaced without fear of breaking the rest of the interface.
Key Idea A view can be partitioned into subviews.
13.5.1 Implementing
NimView
NimView
is the overall view of the game. It is composed of the three sub-views for the players and the pile size. NimView does not (directly) display information about the model nor does it (directly) update the model. Both of those tasks are delegated to the sub-views. NimViews only task is to organize the sub-views in a panel. In the following ways, it is a degenerate view. It doesnt need an instance variable storing a reference to the model. It doesnt have any controllers to construct or register. It doesnt need to register itself with the model. As seen in Listing 13-14, all NimView does is instantiate and lay out the sub-views.
690
Chapter 13 Graphical User Interfaces
Listing 13-14: NimView, a view consisting of three sub-views.
Find The Code ch13/nimMultiView/
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
import import import import
javax.swing.JPanel; javax.swing.BorderFactory; java.awt.GridLayout; java.awt.BorderLayout;
/** Provide a view of the game of Nim to a user. * * @author Byron Weber Becker */
public class NimView extends JPanel {
/** Construct the view. * @param aModel The model we will be displaying. */
public NimView(NimModel aModel) { super();
// Create the sub-views.
NimPlayerView red = new NimPlayerView(aModel, Player.RED); NimPlayerView black = new NimPlayerView(aModel, Player.BLACK); NimPileView pile = new NimPileView(aModel);
// put a title on each sub-view
red.setBorder(BorderFactory.createTitledBorder("Red")); black.setBorder(BorderFactory.createTitledBorder("Black")); pile.setBorder(BorderFactory.createTitledBorder("Pile Size"));
// group the red and black views
JPanel center = new JPanel(); center.setLayout(new GridLayout(1, 2)); center.add(red); center.add(black);
// lay out the pieces in this view
this.setLayout(new BorderLayout()); this.add(center, BorderLayout.CENTER); this.add(pile, BorderLayout.SOUTH); } }
13.5.2 Implementing
NimPileView
The NimPileView class, shown in Listing 13-15, is a simple view. It does not need to update the model, so there are no controllers. It only has a JLabel that is updated via the updateView method. addView is called at line 17 to add this view to the models list of views.
13.5 Using Multiple Views
Listing 13-15: The NimPileView class. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
691
import becker.util.IView; import javax.swing.*; import java.awt.Font;
/** A view showing the current pile size for the game of Nim. * * @author Byron Weber Becker */
Find The Code ch13/nimMultiView/
public class NimPileView extends JPanel implements IView { private NimModel model; private JLabel pileSize = new JLabel();
/** Construct the view. */
public NimPileView(NimModel aModel) { super(); this.model = aModel; this.layoutView(); this.model.addView(this); this.updateView(); }
/** Update the view. Called by the model when its state changes. */
public void updateView() { this.pileSize.setText("" + this.model.getPileSize()); }
/** Layout the view. */
private void layoutView() { this.pileSize.setFont(new Font("Serif", Font.PLAIN, 24)); this.add(this.pileSize); } }
13.5.3 Implementing
NimPlayerView
NimPlayerView
is a full-fledged view. It has its own components to lay out within itself. Those components are used to update the model, so they need to have controllers registered. The view also displays part of the state of the modelwhos turn it is and who has wonand so it needs an updateView method and an instance variable to store a reference to the model. Well write NimPlayerView so that one instance of the class can be used for the red player and a second instance for the black player. To meet this goal it must store the player it represents (lines 14 and 29 of Listing 13-16). The player is used in the updateView method (lines 45 and 48) to determine which buttons to enable and whether a winner should be declared. The view has three buttons for user interaction. They all need to be added to the view, enabled and disabled as appropriate, and have controllers registered. These tasks are all made easier by placing the buttons in an array (lines 16-20) and using loops (lines 43-46, 58-61, and 69-72).
692
Chapter 13 Graphical User Interfaces
Listing 13-16: The NimPlayerView class. 1 import becker.util.IView; 2 import javax.swing.JPanel; 3 import javax.swing.JButton; 4 import javax.swing.JLabel; 5 import javax.swing.SwingConstants; 6 import java.awt.Font; 7 import java.awt.GridLayout; 8 9 /** Provide a view of the game of Nim focused on one particular player to a user. 10 * 11 * @author Byron Weber Becker */ 12 public class NimPlayerView extends JPanel implements IView 13 { private NimModel model; 14 private Player player; 15 16 private JButton[] removeButtons = new JButton[] { 17 new JButton("Remove 1 Token"), 18 new JButton("Remove 2 Tokens"), 19 new JButton("Remove 3 Tokens") 20 }; 21 private JLabel winner = new JLabel("Winner!"); 22 23 /** Construct a view for one player. 24 * @param aModel The game's model. 25 * @param player The player for which this is the view. */ 26 public NimPlayerView(NimModel aModel, Player aPlayer) 27 { super(); 28 this.model = aModel; 29 this.player = aPlayer; 30 31 this.layoutView(); 32 this.registerControllers(); 33 34 this.model.addView(this); 35 this.updateView(); 36 } 37 38 /** Update the view to reflect recent changes in the model's state. */ 39 public void updateView() 40 { Player whoseTurn = this.model.getWhoseTurn(); 41 int pSize = this.model.getPileSize(); 42 // Enable buttons if it's my player's turn and there are enough tokens on the pile. for (int i = 0; i < this.removeButtons.length; i++) 43 44 { this.removeButtons[i].setEnabled( 45 whoseTurn == this.player && i + 1 <= pSize); 46 } 47 this.winner.setVisible( 48 this.model.getWinner() == this.player); 49 } 50 continued...
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.5 Using Multiple Views
Listing 13-16 continued 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 } /** Lay out the components for this view. */
693
private void layoutView() { GridLayout grid = new GridLayout(4, 1, 5, 5); this.setLayout(grid); Font font = new Font("Serif", Font.PLAIN, 24); for (JButton b : this.removeButtons) { this.add(b); b.setFont(font); } this.winner.setFont(font); this.add(this.winner); }
/** Register controllers for this view's components. */
private void registerControllers() { for (int i = 0; i < this.removeButtons.length; i++) { this.removeButtons[i].addActionListener( new RemoveButtonController(this.model, i + 1)); } }
Like JTextField, JButton objects use an ActionListener. When the button is clicked, it calls the actionPerformed method for all the listeners that have been added. Recall that it is inside the actionPerformed method that we specify the code to execute when the button is clicked. This is where we call the removeTokens method in the model. In our previous controller the user typed the number of tokens to remove from the pile. We need a different way to find out how many tokens to remove. One approach is to have a separate controller object for each button. The controller has an instance variable that remembers how many tokens to remove. That instance variable is set, of course, when the controller is constructed. We can see this at line 71 of Listing 13-16 where a new controller is instantiated for each button. The revised controller class is shown in Listing 13-17.
694
Chapter 13 Graphical User Interfaces
Listing 13-17: The controller for the JButtons used to remove tokens. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import java.awt.event.*;
/** A controller to remove tokesn from the game of Nim. * * @author Byron Weber Becker */
public class RemoveButtonController extends Object implements ActionListener { private NimModel model; private int numRemove;
/** Construct an instance of the cotroller. * @param aModel The model this controls. * @param howMany How many tokens to remove when the button is clicked. */
public RemoveButtonController(NimModel aModel, int howMany) { super(); this.model = aModel; this.numRemove = howMany; }
/** Remove the right number of tokens from the model. */
For use by CS349|SE382 Only
public void actionPerformed(ActionEvent e) { this.model.removeTokens(this.numRemove); } }
13.5.4 Sequence Diagrams
Removing a token involves six interacting classes. This is a level of complexity that we havent seen before, but is not uncommon. To keep things in perspective its important to think locally. For each method we can ask, what is the job that this method has to do? What services does it need from other classes to do that job? But a global perspective can help, too. Figure 13-10 is a sequence diagram that can help visualize the objects involved in removing a token and the sequence of actions taking place. The six objects involved are shown at the top of the diagram, each with their class name. In the case of NimPlayerView there are two, so we distinguish between the instance for the red player and the instance for the black player. There are six JButton objects, but it isnt important to distinguish between them, so only one is shown. The dashed line extending down from each object is its lifeline. In a complete sequence diagram, the lifeline would begin with the objects construction and end when the object was no longer needed. The boxes along the lifeline represent a method executing in that object. The solid arrows between the boxes represent one method calling another. A dashed arrow with an open arrowhead represents a method finishing execution and returning to its caller.
University of Waterloo, Waterloo, Ontario
13.5 Using Multiple Views
695
Figure 13-10: A sequence diagram of the actions involved in removing tokens and updating the views.
NimPlayerView (red)
NimPileView
JButton handleEvent
Controller
NimModel
NimPlayerView (black)
actionPerformed
removeTokens
updateAllViews updateView get... get...
updateView getWhoseTurn getPileSize
updateView getPileSize
Putting all this together, the diagram begins in the upper-left corner with the method in JButton being called, presumably because the user clicked the button. handleEvent calls the actionPerformed method in the controller. We can think of the actionPerformed method as executing for quite a whileall the time that it takes to call removeTokens, including the calls that removeTokens makes. This length of time is represented by the length of the box on the controllers lifeline.
handleEvent
696
Chapter 13 Graphical User Interfaces On the lifeline for NimModel, we see that the longest box, corresponding to calls a helper method in the same class, updateAllViews. This helper method calls all the updateView methods in the views registered with NimModel. Each of these, of course, call additional methods. By the time execution returns to the handleEvent method in JButton at the bottom-left corner of the diagram, tokens have been removed from the model and all of the views have been updated accordingly.
removeTokens,
13.6 Controller Variations
Three techniques are often used to simplify writing controllers. One nests the controller class inside the views class. The second makes use of information passed in the event objects. The third is a short-cut often taken in sample code in other books and on the Internet.
13.6.1 Using Inner Classes
An inner class is a class that is nested inside another class2. Inner classes are most useful for defining small helper classes that are very specific to a particular task. By placing inner classes inside the class they are helping, we can make that relationship more explicit and keep the definition of the helper class very close to the class it is helping. Beyond this, the primary advantage of an inner class is that it can access the methods and instance variables of its enclosing classeven the private methods and instance variables! Views are usually written with inner classes for the controllers. Listing 13-18 shows the NimPlayerView (Listing 13-16) and RemoveButtonController (Listing 13-17) combined in a single file by making the controller an inner class. The first thing to notice about Listing 13-18 is that RemoveButtonController falls between the opening and closing braces of the NimPlayerView class. The actual order of instance variables, methods, and inner classes within the outer class doesnt matter to the compiler, but inner classes are generally placed at the end.
Key Idea An inner class can access instance variables and methods of its enclosing class. Key Idea An inner class is placed inside another class, but outside of all methods.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
2
There are actually four varieties of inner classes. We will focus on member classes. The other three are nested top-level classes, local classes, and anonymous classes.
13.6 Controller Variations
Listing 13-18: Using an inner class for a views controller. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // Import classes needed by both view and controller.
697
public class NimPlayerView extends JPanel implements IView { private NimModel model;
// Other instance variables, constructor, updateView, and layoutView are omitted.
private void registerControllers() { for (int i=0; i < this.removeButtons.length; i++) { this.removeButtons[i].addActionListener( new RemoveButtonController(i+1)); } }
// Inner class for the controllers to remove tokens from the pile.
private class RemoveButtonController extends Object implements ActionListener { private int numRemove; public RemoveButtonController(int howMany) { super(); this.numRemove = howMany; } public void actionPerformed(ActionEvent evt) { NimPlayerView.this.model.removeTokens(this.numRemove); } } }
Second, the inner class accesses the model instance variable from the outer class at line 25. The syntax for doing so is a little odd. We cannot write this.model because then we would be referring to an instance variable in the RemoveButtonController class. To access the outer class, first give the name of that class and then access the variable as usual. It is also possible to let the compiler figure it out and write
model.removeTokens(this.numRemove);
For clarity, however, we will always write the longer version. Third, because the inner class can access the model via the outer class, the model instance variable has disappeared along with code in the constructor to initialize it. The argument is also omitted when the constructor is called in line 10. Each instance of the inner class is tied to a specific instance of the outer class. For example, the game creates two instances of NimPlayerView, one for the red player and one for the black player. Both of these objects create three controllers. The controllers created for reds instance of the view are forever tied to that instance. They will access the methods and instance variables in reds instance of the view and will never access those in blacks instance.
698
Chapter 13 Graphical User Interfaces
13.6.2 Using Event Objects
The actionPerformed method is always passed an ActionEvent object which provides more details about the users action. All of the methods in all of the listener interfaces have an event object as a parameter. One of the most useful items of information in an event object is the source of the eventthat is, which component was manipulated by the user. Using that information, we can figure out how many tokens to remove without using an instance variable in the controller class. Well simply compare the source to each JButton in the array. When we have a match, well know how many tokens to remove. With this approach, the controller will have no instance variables at all. This has two implications. First, there are no instance variables to initialize and we can let Java provide a default constructor for us3. Second, every instance is just like all the other instances and we can use the same controller for all three buttons. Listing 13-19 shows how.
Key Idea Use event objects to obtain more information about the event and the source that generated it.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
3
Omitting the parameterless or default constructor is an option for every class, but we have always included it, when applicable, for clarity. Controllers are usually so small and specialized, however, that we can omit them without loss of clarity.
13.6 Controller Variations
Listing 13-19: A controller that uses the event object to avoid instance variables. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // Import classes need by both view and controller.
699
public class NimPlayerView extends JPanel implements IView { private NimModel model; private JButton[] removeButtons = new JButton[] { new JButton("Remove 1 Token"), new JButton("Remove 2 Tokens"), new JButton("Remove 3 Tokens") };
// Other instance variables, constructor, updateView, and layoutView are omitted. /** Register controllers for this view's components. */
Find The Code ch13/nimInnerClass/
private void registerControllers() { RemoveButtonController controller = new RemoveButtonController(); for (int i = 0; i < this.removeButtons.length; i++) { this.removeButtons[i].addActionListener(controller); } } private class RemoveButtonController extends Object implements ActionListener { public void actionPerformed(ActionEvent evt) { JButton src = (JButton)evt.getSource(); if (src == removeButtons[0]) { model.removeTokens(1); } else if (src == removeButtons[1]) { model.removeTokens(2); } else if (src == removeButtons[2]) { model.removeTokens(3); } else { assert false; // Shouldn't happen! } } } }
Note in line 24 that the getSource method returns an Object which must be cast to an appropriate type. The source itself will often have useful information. For example, if it were a text field, we could get the text typed by the user. The cascaded-if structure in lines 25-33 is fine for a small number of components, but if the components are stored in an array a loop can be more concise, as follows:
700
Chapter 13 Graphical User Interfaces
public void actionPerformed(ActionEvent evt) { JButton src = (JButton)evt.getSource(); int i = 0; while (removeButtons[i] != src) { i++; } assert removeButtons[i] == src; model.removeTokens(i+1); }
13.6.3 Integrating the Controller and View
Key Idea This is not a recommended approach, but its use is widespread.
For use by CS349|SE382 Only
The controller and view can also be integrated into the same class without the use of an inner class. Many examples on the Web use this approach because it is quick and easy. It introduces a significant disadvantage, however, in that there is only one controller for all of the various components. With the previous techniques, you can easily write one controller for a JButton and a different controller for a JTextField. Each controller has its own actionPerformed method that is specific to a particular task. When the controller and view are integrated, a single actionPerformed method must handle both components. In terms of the software engineering principles studied in Section 11.3.2, such integration reduces the cohesion of the methods (recall that we want high cohesion). Nevertheless, the technique is shown here so you can understand it if and when you see it. The technique works by implementing the required interfaces in the view class itself. In Listing 13-20, the ActionListener interface is listed on the class header (lines 2-3) and its only method, actionPerformed, is implemented at lines 14-24 just like any other method. Note that there is no inner class. The controller is registered with the JButton objects in line 10. Instead of constructing a separate object, a reference to the view itself (that is, this) is passed to the button.
University of Waterloo, Waterloo, Ontario
13.7 Other Components
Listing 13-20: A version of NimPlayerView that integrates the view and the controller. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // import classes need by both view and controller
701
public class NimPlayerView extends JPanel implements IView, ActionListener { // other instance variables, as before
// constructor, updateView, and layoutView as before /** Register controllers for this view's components. */
Find The Code ch13/nimIntegrated/
private void registerControllers() { for (int i = 0; i < this.removeButtons.length; i++) { this.removeButtons[i].addActionListener(this); } } public void actionPerformed(ActionEvent evt) { JButton src = (JButton)evt.getSource(); int i = 0; while (removeButtons[i] != src) { i++; } assert removeButtons[i] == src; model.removeTokens(i+1); } }
13.7 Other Components
So far we have only worked with JTextField and JButton components. But there are many more components, too many to cover in a book such as this. So how can you learn to use them? Use the following strategies: Discover what components are available and might be applicable. Identify the listeners used. Skim the documentation. Begin with sample code. Work incrementally. In the following sections well use these strategies to learn how to display a set of color names to use in Nim instead of Red and Black.
13.7.1 Discover Available Components
There are several ways to discover available components. One is to look at the Visual Index to the Swing Components. It can be found at
http://java.sun.com/docs/books/tutorial/uiswing/components/compon ents.html. It shows a sample of each component and has links to documentation
where you can learn more. Figure 13-11 shows a part of the web page that looks promising. It appears that at least two kinds of components can display lists of color names, as we would like to do.
702
Chapter 13 Graphical User Interfaces Clicking the links labeled Combo box and List leads to pages titled How to Use Combo Boxes and How to Use Lists. The first page refers to the component JComboBox and the second page refers to JList.
Figure 13-11: A part of A Visual Index to the Swing Components.
For use by CS349|SE382 Only
Another option is to find one of several demonstration programs available. One that comes with this textbook is shown in Figure 13-5 on page 673. If you have downloaded the example code for the textbook, youll find the code in the directory gui/componentDemo. Running the program and playing with the components will show that JSpinner is also a possibility. In Figure 13-5 it displays Monday but it also spins through the other days of the week. It could also spin through the color names we want to display. Any of these three options could work for us. Choosing between them is largely a matter of personal taste. For now, well choose JList.
13.7.2 Identify Listeners
When we identify the listeners for a component, we identify what kind of events it can tell us about and thus what kind of controllers we can write. Every component may have the following six kinds of listeners: Component listeners listen for changes in the components size, position, or visibility. Component listeners have methods like componentHidden, componentResized, and componentMoved. Focus listeners listen for the component gaining or losing the ability to receive keyboard input. Focus listeners have two methods, focusGained and focusLost. Key listeners listen for key press events. Such events are fired only by the component that has the keyboard focus. Key listeners have keyPressed, keyReleased, and keyTyped methods. Mouse listeners listen for mouse clicks and the mouse moving in to and out of the components drawing area. Mouse listeners have five methods, including mouseEntered and mouseClicked. Mouse motion listeners listen for changes in the cursors position within the component. Such listeners have two methods, mouseMoved and mouseDragged.
University of Waterloo, Waterloo, Ontario
13.7 Other Components Mouse wheel listeners listen for mouse wheel movement over the component. They have a single method, mouseWheelMoved. In addition to these six listeners, components have one or more additional listeners that vary by component type. For example, we have already seen that JTextField and JButton objects can have ActionListeners. A complete table of components and listeners is maintained by the creators of Java at http://java.sun.com/docs/books/tutorial/uiswing/events/event sandcomponents.html. It is summarized in Figure 13-12. From it we can tell that the JList component uses a ListSelectionListener and one or more unspecified listeners. Another approach is to look at the documentation for the component at http://java.sun.com/j2se/1.5.0/docs/api/. For example, find JList in the left side and click on it. Scroll down to the list of methods and look for methods named addXxxxListener where the Xxxx can vary. JList has an addListSelectionListener method. The documentation for ListSelectionListener says the interface specifies a single method, valueChanged. This is the method that our controller for JList will need to implement.
703
704
Chapter 13 Graphical User Interfaces
Figure 13-12: Listeners used by some of Javas GUI components.
Component
JButton JCheckBox JColorChooser JComboBox JDialog JEditorPane JFileChooser JFormattedTextField
For use by CS349|SE382 Only
JFrame JList JMenu JMenuItem JPasswordField JPopupMenu JProgressBar JRadioButton
University of Waterloo, Waterloo, Ontario
JSlider JSpinner JTabbedPane JTable JTextArea JTextField JToggleButton JTree
13.7.3 Skim the Documentation
There are two primary sources of information for working with Javas GUI components: the API documentation and the Java Tutorial.
Ac ti o n Ca Li re ste tL n Ch ist er an ene D geL r oc is um ten e e It em ntL r is L Li iste ten e st Se ner r W lect in i do onL w L is O te th er iste ne ne r r
13.7 Other Components
705
Application Programming Interface (API) Documentation
One primary source of information is the API or Application Programming Interface documentation. It is the class-by-class documentation found at http://java.sun.com/j2se/1.5.0/docs/api/. The documentation for each class gives an overview of the class, its inheritance hierarchy, a list of the constructors provided and a list of the methods provided, including detailed descriptions of what they do. The first time you use a component, skim this documentation looking for methods that sound useful. There may be lots of themdont get overwhelmed! For JList, the documentation lists about 70 methods, plus the 344 methods it inherits from its superclasses. Whats important to get started using a JList? Constructing the component, adding items to display in the list, adding a listener, and finding out which item on the list was selected. Skimming the documentation for methods that sound relevant yields the following: JList(): constructs an empty JList. JList(Object[] listData): constructs a JList that displays the elements in the specified array. addListSelectionListener: adds a listener to the JList. getSelectedIndex: returns the index of the first selected item; if nothing is selected it returns -1. getSelectedIndicies: returns an array of all the selected indices. getSelectedValue: returns the first selected value. These methods answer most of our questions. We might have expected to find an add item method to add items to the list, but we didnt. Instead, it appears that we pass an array of items to display when the component is constructed. It also appears that several items can be selected at one time. We may want to make note of that for later reference.
Key Idea The API documentation provides full details about each class.
The Java Tutorial
The Java Tutorial at http://java.sun.com/docs/books/tutorial/ provides a wealth of practical examples for creating graphical user interfaces. Particularly relevant is the Creating a GUI with JFC/Swing chapter. It contains sections such as Learning Swing by Example, Using Swing Components, and Writing Event Listeners. One subsection, at
http://java.sun.com/docs/books/tutorial/uiswing/components/compon entlist.html, contains a long list of topics with names like How to Make ApKey Idea The Java Tutorial contains lots of sample code.
plets, How to Use Lists, and so on. The API documentation often provides links directly to these sections of the tutorial. Clicking the How to Use Lists link opens a document that includes sample code and sections titled Initializing a List, Selecting Items in a List, and Adding Items to and Removing Items from a List. All sound helpful!
706
Chapter 13 Graphical User Interfaces
13.7.4 Begin with Sample Code
Building on the discoveries of someone else is always easier than starting from scratch yourself. When learning to use a new component, look for sample code using it. The Java Tutorial is a good place to look, particularly in the How to sections referenced earlier. Another source for sample code that matches the style presented in this textbook is the componentDemo program shown in Figure 13-5 on page 673. If you run the program and click an element in the JList, an entry is added to the table at the bottom of the frame. The view column says ListView. This is the name of the class containing the JList. The second column, Listener, says ListView$ListController. Thats the name of the controller class that handled your mouse clickthe ListController class that is an inner class within the ListView class. Open the source for ListView and youll find the code constructing the JList, laying it out within a view, registering a controller, and the code for the controller itself. Much of this code can be cut and pasted directly into the program youre writing.
For use by CS349|SE382 Only
13.7.5 Work Incrementally
The last piece of advice is to work incrementally. Start with small goals for the component. Meet those goals and then move on to more ambitious goals. For example, you might begin by displaying the JList in a view. Listing 13-21 shows a minimal view with the goal of showing a JList with the names of some colors and to detect when one has been selected.
University of Waterloo, Waterloo, Ontario
13.7 Other Components
Listing 13-21: A simple view to display a list of colors and detect when one is selected. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
707
import import import import import
becker.util.IView; javax.swing.JPanel; javax.swing.JList; javax.swing.event.ListSelectionEvent; javax.swing.event.ListSelectionListener;
Find The Code ch13/usingJList/
public class View extends JPanel implements IView { // private Object model; private JList list; public View(Object aModel) { super();
// this.model = aModel;
this.layoutView(); this.registerControllers();
// this.model.addView(this);
this.updateView(); } public void updateView() {// Statements to update the components in the view. } private void layoutView() { this.list = new JList(new String[] {"Red", "Green", "Blue", "Yellow", "Orange", "Pink", "Black"}); this.add(this.list); } private void registerControllers() { this.list.addListSelectionListener( new ListController()); } private class ListController extends Object implements ListSelectionListener { public void valueChanged(ListSelectionEvent evt) { System.out.println( "selected " + View.this.list.getSelectedValue()); } } }
Running a program that places this view in a frame appears as shown in Figure 13-13 and proves that we have made significant progress. The list shows the seven colors and it prints a message when one is selected. However, there are two problems. First, each time a color is selected, two copies of the message are printed by the controller. Second, the list has no scroll bars. If the window is made smaller than the list, part of the list simply disappears.
708
Chapter 13 Graphical User Interfaces For the first problem, it seems like the documentation Figure 13-13: Running the JList test. would be a good place to start. After all, the listener contains the code that is being called twice. However, that documentation has nothing of help. If we look at the ListSelectionEvent documentation, we find a method named getValueIsAdjusting. Its description says Returns true if this is one of multiple change events, which sounds promising. JList reports a list selection event when the mouse is pressedand when it is released, and several more events in between if the user moves the mouse over different values in the list. Rewriting our controllers valueChanged method results in only one message being printed, the one selected when the mouse button is released:
ListSelectionListener public void valueChanged(ListSelectionEvent evt) { if (!evt.getValueIsAdjusting()) { System.out.println( "selected " + View.this.list.getSelectedValue()); } }
For use by CS349|SE382 Only
The problem of the missing scroll bars can be solved by searching the JList class documentation for scroll. That search finds the following:
JList JList
doesn't support scrolling directly. To create a scrolling list you make the the viewport view of a JScrollPane. For example:
JScrollPane scrollPane = new JScrollPane(dataList);
University of Waterloo, Waterloo, Ontario
Key Idea Component size problems are often related to the layout manager.
where dataList is the instance of JList you want to display. The JScrollPane component is added to the view instead of the JList. Working incrementally, we add equivalent code to the layoutView method in Listing 13-21 and run the program to see the results. Unfortunately, nothing has changed and scroll bars still do not appear. It turns out that JPanels default layout manager, FlowLayout, allows the list to take up as much space as it requests. JScrollPane does not show the scroll bars until the available space is less than the requested space. BorderLayout is a layout manager that forces its components to fit within the available space. Using it to manage the views layout results in the scroll bars appearing when the JList is small. The resulting code for layoutView is as follows:
13.8 Graphical Views
709
private void layoutView() { this.setLayout(new BorderLayout()); this.list = new JList(new String[] {"Red", "Green", "Blue", "Yellow", "Orange", "Pink", "Black"}); JScrollPane scrollpane = new JScrollPane(this.list); this.add(scrollpane, BorderLayout.CENTER); }
As shown here, it is unrealistic to expect to understand and use a complex class like JList on the first try. An excellent strategy is to work incrementally. Understand and implement the basics, make note of the remaining issues, and then solve them one at a time. Using this strategy we are well on the way to making effective use of the JList component. Reasonable next steps include making calls to the model in response to user selections and, if required, learning how to add new values to the list while the program is running.
13.8 Graphical Views
Many components are available for Java programs, but sometimes none of them are quite right for a particular application. In those cases, you may need to make your own. We have, in fact, already done this. In Section 6.7 we wrote the Thermometer class which displayed a temperature using an image of a thermometer. In Section 13.8.1 we will implement a similar class to simply display a pile of tokens for the game of Nim. In Section 13.8.2 we will go a step further and add a listener for mouse events so the user can use our new component to select the tokens to remove from the pile.
13.8.1 Painting a Component
Instances of our custom component, PileComponent, represent a pile of tokens as circles, drawn one on top of the other as shown in Figure 13-14. Such a component that does its own painting usually extends the JComponent class. See Listing 13-22. Two crucial parts of the class are instance variables used to either store or acquire the information required to do the painting (lines 4-5), and the paintComponent method (lines 26-44).
710
Chapter 13 Graphical User Interfaces Two instance variables are required: stores the actual number of to- Figure 13-14: A custom component representing a pile of tokens for Nim. kens to display; maxTokens stores the maximum number that could be displayed. The maximum is used to scale the circles appropriately. It is set with the constructor. numTokens is set using a mutator method, setPileSize, called from the updateView method in the view that contains the PileComponent object. When the pile size is changed, this.repaint() must be called. It tells the Java system that it should call paintComponent as soon as possible to redraw the pile. The paintComponent method begins by calculating useful values for painting (lines 29-32). The first two merely make temporary copies of the components width and height to make them easier to use. The second two calculate the diameter of each token and where the left side will be painted. Lines 35-36 erase whatever image the component was displaying by filling the entire drawing area with the background color. Lines 39-43 redraw all of the tokens from bottom to top. One other detail is setting the minimum and preferred size of the component in lines 12 and 13. Without these statements the components size will default to a barely visible 1 x 1 pixel square.
numTokens
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.8 Graphical Views
711
Listing 13-22: A component that displays the size of a token pile graphically. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 // Import statements omitted.
public class PileComponent extends JComponent { private int numTokens = 0; private int maxTokens;
/** Create a new component. * @param max The maximum number of tokens that can be displayed. */
Find The Code ch13/nimMultiView/
public PileComponent(int max) { super(); this.maxTokens = max; this.setMinimumSize(new Dimension(40, 60)); this.setPreferredSize(new Dimension(60, 90)); }
/** Reset the size of the pile. * @param num The new pile size. 0 <= num <= maxTokens */
public void setPileSize(int num) { if (num < 0 || num > this.maxTokens) { throw new IllegalArgumentException("too many/few tokens"); } this.numTokens = num; this.repaint(); }
/** Paint the component. */
public void paintComponent(Graphics g) { // Values to use in painting. int width = this.getWidth(); int height = this.getHeight(); int tokenDia = Math.min(width, height/this.maxTokens); int tokenLeft = width/2 - tokenDia;
// Erase the existing images.
g.setColor(this.getBackground()); g.fillRect(0, 0, width, height);
// Draw the tokens.
g.setColor(Color.BLACK); for (int i = 0; i < this.numTokens; i++) { int top = height - (i + 1) * tokenDia; g.fillOval(tokenLeft, top, tokenDia, tokenDia); } } }
712
Chapter 13 Graphical User Interfaces
13.8.2 Making a Graphical Component Interactive
We can make PileComponent interactive, enabling users to use the mouse to select a Figure 13-15: The sequence of mouse actions triggering a selection. number of tokens by performing the following steps, also illustrated in Figure 13-15. mouse The steps are: pressed Press the mouse button. Drag the mouse over some of the tokens displayed by the component. Release the mouse button. In general, implementing a custom component involves the five steps shown in Figure 13-16. The result is a component we mouse can use in a view, complete with its own released controllersjust like we use controllers with JTextField and JButton components. You may notice similarities with what we have done before. For example, both a component and a model call a method when their state is changed (step 3) and both have a list of objects to inform when something significant happens (step 4). On the other hand, a component is also similar to a view. Both extend a kind of component (JPanel versus JComponent in step 1) and both have listeners (step 5, although in a view the listeners are called controllers).
e us mo gged dra
Figure 13-16: Steps to implement an interactive component.
For use by CS349|SE382 Only
Key Idea A component has features in common with both models and views.
University of Waterloo, Waterloo, Ontario
1. Write a class that extends JComponent. 2. Declare instance variables to store the information required to paint the component appropriately. Override the paintComponent method to do the painting. 3. Write mutator methods to update the instance variables. Call the repaint method before exiting any method that changes the components state. 4. Declare a list to store the components listeners. Include methods to add and remove components from the list, and a handleEvent method to inform all listeners of a significant event. 5. Write and register listeners to detect and respond to the users actions. The first three steps in Figure 13-16 were already done in the earlier version of In the following subsections we will discuss steps 4 and 5 in more detail, referring to Listing 13-23 which contains the code for the completed component. This new, interactive version of PileComponent will be called PileComponent2.
PileComponent.
13.8 Graphical Views
713
Informing the Components Listeners
When our component is used in a view, we will want to add controllers to it that update the model. They will implement an interface such as ActionListener or ListSelectionListener. Now, because we are writing the component, we can choose which listener interface to use. Of all the listeners listed in Figure 13-12, ActionListener seems the most appropriate. Therefore, in lines 22-23 of Listing 13-23 we declare an ArrayList to store In lines 45-48 we provide an objects implementing ActionListener. addActionListener method, like the one provided in JButton and JTextField. A complete implementation would also provide a removeActionListener method. In lines 105-112 we provide a private method named handleEvent, to be called when the component detects the user selecting some tokens. It constructs an ActionEvent object and then loops through all the registered controllers, calling their actionPerformed method and passing the event object.
Looking Back In Figure 13-8 shows a simplified version of JTextField. It also has a handleEvent method.
Writing and Registering Listeners
The last step, and the most complicated one, is figuring out when to call the handleEvent method. To do so, we will write two inner classes implementing MouseListener and MouseMotionListener. The first listener4 will be informed each time something happens to the mouse button. The second one will be informed each time the mouse moves. Mouse-related events are split into two listeners because there are many motion events. If the component only cares about mouse clicks we dont want to incur the overhead associated with mouse motion events. We need to detect the following three mouse events: When the mouse button is pressed we will create a new rectangle that will bound the area (and tokens) selected. When the mouse is dragged we will update the size of the bounding rectangle and repaint the component to show it. When the mouse button is released we will update the size of the bounding rectangle one last time and then call the handleEvent method to inform all the registered controllers. These three steps are performed in the mousePressed, mouseDragged, and mouseReleased methods, respectively. They are found in lines 125-129, 148-152, and 131-137 of Listing 13-23. All three use the getPoint method in the event object to find out where the mouse was when the event occurred. Of course, the component should provide feedback on which tokens have been selected. This is accomplished in the paintComponent method. Lines 75-79 draw the bounding rectangle and lines 86-88 determines if it surrounds the token currently being drawn. If it is, an instance variable is incremented and the tokens
4
We use the term listener rather than controller because these classes will not be interacting with the programs model.
714
Chapter 13 Graphical User Interfaces color is changed to yellow. An accessor method, getNumSelected, is provided to allow clients to get the number of selected tokens.
Listing 13-23: An interactive component that allows the user to select a number of tokens.
Find The Code ch13/nimMultiView/
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
1 import javax.swing.JComponent; 2 import java.awt.Graphics; 3 import java.awt.Insets; 4 import java.awt.Dimension; 5 import java.awt.Point; 6 import java.awt.Color; 7 import java.awt.Rectangle; 8 import java.awt.event.MouseListener; 9 import java.awt.event.MouseMotionListener; 10 import java.awt.event.MouseEvent; 11 import java.awt.event.ActionListener; 12 import java.awt.event.ActionEvent; 13 import java.util.ArrayList; 14 15 /** A component that displays a pile of tokens and allows the user to select a number of 16 * them. It informs registered listeners when tokens have been selected. Allows the 17 * client to change the number of tokens in the pile. 18 * 19 * @author Byron Weber Becker */ 20 public class PileComponent2 extends JComponent 21 { // Store the controllers to inform when a selection takes place. 22 private ArrayList<ActionListener> actionListeners = 23 new ArrayList<ActionListener>(); 24 25 // Information for painting the component. 26 private int numTokens = 0; 27 private int maxTokens; 28 29 private Rectangle selection = null; // selected area 30 private int numSelected = 0; // # tokens in selected area 31 continued...
13.8 Graphical Views
Listing 13-23 continued 32 /** Create a new component. 33 * @param maxTokens The maximum number of tokens that can be displayed. */ 34 public PileComponent2(int maxTokens) 35 { super(); 36 this.maxTokens = maxTokens; 37 this.setMinimumSize(new Dimension(40, 60)); 38 this.setPreferredSize(new Dimension(60, 90)); 39 40 // Add the mouse listener. this.addMouseListener(new MListener()); 41 42 this.addMouseMotionListener(new MMListener()); 43 } 44 45 /** Add an action listener to this components list of listeners. */ 46 public void addActionListener(ActionListener listener) 47 { this.actionListeners.add(listener); 48 } 49 50 /** Set the size of the pile. 51 * @param num The new pile size. 0 <= num <= maxTokens */ 52 public void setPileSize(int num) 53 { if (num < 0 || num > this.maxTokens) 54 { throw new IllegalArgumentException("too many/few tokens"); 55 } 56 this.numTokens = num; 57 this.selection = null; 58 this.numSelected = 0; 59 this.repaint(); 60 } 61 62 /** Paint the component. */ 63 public void paintComponent(Graphics g) 64 { // Values to use in painting. int width = this.getWidth(); 65 66 int height = this.getHeight(); 67 int tokenDia = Math.min(width, height/this.maxTokens); 68 int tokenLeft = width/2 - tokenDia; 69 70 // Erase the existing images. g.setColor(this.getBackground()); 71 72 g.fillRect(0, 0, width, height); 73 74 // Draw the selection rectangle, if there is one. g.setColor(Color.BLACK); 75 76 if (this.selection != null) 77 { Rectangle sel = this.selection; 78 g.drawRect(sel.x, sel.y, sel.width, sel.height); 79 } 80 continued...
715
716
Chapter 13 Graphical User Interfaces
Listing 13-23 continued 81 // Draw the tokens. Detect which ones are selected. Count them 82 // and color them differently. this.numSelected = 0; 83 84 for (int i = 0; i < this.numTokens; i++) 85 { int top = height - (i + 1) * tokenDia; 86 if (this.selection != null && 87 this.selection.contains(tokenLeft+tokenDia/2, 88 top + tokenDia / 2)) 89 { this.numSelected++; 90 g.setColor(Color.YELLOW); 91 } else 92 { g.setColor(Color.BLACK); 93 } 94 95 g.fillOval(tokenLeft, top, tokenDia, tokenDia); 96 } 97 } 98 99 /** Get the number of tokens currently selected. 100 * @return the number of tokens currently selected */ 101 public int getNumSelected() 102 { return this.numSelected; 103 } 104 105 /** A helper method to inform all listeners that a selection has been made. */ 106 private void handleEvent() 107 { ActionEvent evt = new ActionEvent( 108 this, ActionEvent.ACTION_PERFORMED, ""); 109 for (ActionListener al : this.actionListeners) 110 { al.actionPerformed(evt); 111 } 112 } 113 114 /** Adjust the selection's size. */ 115 private void adjustSelectionSize(Point mPos) 116 { this.selection.setSize(mPos.x - this.selection.x, 117 mPos.y - this.selection.y); 118 this.repaint(); 119 } 120 121 /** Listen for mouse events within the pile. */ 122 private class MListener extends Object 123 implements MouseListener 124 { 125 /** A mousePressed event signals the beginning of a selection. */ 126 public void mousePressed(MouseEvent e) 127 { PileComponent2.this.selection = 128 new Rectangle(e.getPoint()); 129 } continued...
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.9 Patterns
Listing 13-23 continued 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 } /** A mouseReleased event signals the end of a selection. Finish up the * selection and inform the listeners. */
717
public void mouseReleased(MouseEvent e) { PileComponent2.this.adjustSelectionSize( e.getPoint()); PileComponent2.this.handleEvent(); } public void mouseClicked(MouseEvent e) public void mouseEntered(MouseEvent e) public void mouseExited(MouseEvent e) }
/** Listen for mouse events within the pile. */
{} {} {}
private class MMListener extends Object implements MouseMotionListener {
/** The bounds of the selection's rectangle changed. Adjust it. */
public void mouseDragged(MouseEvent e) { PileComponent2.this.adjustSelectionSize( e.getPoint()); } public void mouseMoved(MouseEvent e) } {}
13.9 Patterns
13.9.1 The Model-View-Controller Pattern
Name: Model-View-Controller Context: A program requires a graphical user interface to interact with the user.
You want to program it with the good software engineering principles of encapsulation, information hiding, high cohesion, and low coupling to facilitate future changes. Solution: Organize the program into a model with one or more views and controllers. The model abstracts the problem the program is designed to solve. Each view displays some part of the model to the user while controllers translate user actions in a view into method calls on the model. The Model-View-Controller pattern requires three templates, one for the model, one for the combination of a view and a controller, and one for the main method. Listing 13-13 contains an excellent start on a template for views, but needs an inner class for a controller. Listing 13-1 and Listing 13-3 can be generalized for the models template and the main methods template, respectively. Consequences: Because the model depends only on objects implementing the IView interface, coupling is extremely low. The interface can be changed or even completely replaced, usually without changing the model.
Looking Ahead Problem 13.2 asks you to prepare these templates.
718
Chapter 13 Graphical User Interfaces
Related Patterns:
The Extended Class pattern is used by the views when they extend JPanel. The Has-a (Composition) pattern is used to relate the model to the views and the views to the model. The Process All Elements pattern is used to update all of the views with changes in the model. The Strategy pattern is used to lay out the views components and to provide a controller (listener) that reacts appropriately to events in a particular component.
13.10 Summary and Concept Map
Graphical user interfaces use a library of objects, commonly called components, to interact with users. The program is organized into a model containing the abstractions related to the problem, views that display the model to the user, and controllers that interpret user actions to modify the model. One model may have several views and each view may have several controllers. It is also possible to create our own components to perform specific tasks for which no existing component is available.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.11 Problem Set
719
layout managers
org ani ze the regis pla t trolle er con- ceme nt rs w ar e c of ith om p osed of
views
is d ispl aye ma db yh y ave sev eral
are n up otif dat ied es of by
components
le mp exa re f so
a model
JButton, JTextField
a
to en ist l
controllers
th wi d ere ist reg inner class re a n a as en ritt nw e oft are re a ed event pass methods contain are s peci fied by implement
are cal led by
ActionListener, ListSelectionListener
13.11 Problem Set
Written Exercises
13.1 13.2 Explain how using sub-views (Section 13.5) is good software engineering. Refer specifically to the concepts of cohesion and coupling. Write the three code templates required for the Model-View-Controller pattern. Listing 13-13 contains an excellent start on a template for views, but needs an inner class for a controller. Listing 13-1 and Listing 13-3 can be generalized for the models template and the main methods template, respectively.
is updated by
event objects
are examples of
listener interfaces
720
Chapter 13 Graphical User Interfaces 13.3 Prepare a class diagram showing the relationships between the classes in the Model-View-Controller pattern. Assume the controller has been written in a separate class, as shown in Listing 13-9 implements an ActionListener. List the signatures for all the methods required to implement a WindowListener. The Java library contains two classes named MouseAdapter and MouseMotionAdapter. Discuss how they could be used to simplify the PileComponent2 class shown in Listing 13-23. The Java library contains an interface named MouseInputListener. Examine the documentation and discuss how it could be used in the PileComponent2 class shown in Listing 13-23.
13.4 13.5
13.6
Programming Exercises
13.7 Find the code for the version of Nim with multiple views. a. Add a new view whose function is to offer hints to the current player. (Hint: Assuming the rules where 1, 2, or 3 tokens may be removed, a player who leaves 1, 2, or 3 tokens for his or her opponent has made a serious mistake. Similarly, a player who leaves exactly four tokens is in a very strong position. Generalize these observations.) b. Modify the NimPlayerView class to use a JComboBox for user input instead of JButton objects. c. Modify the NimPlayerView class to use a JSlider for user input. d. Add a new view whose function is to start a new game. The user should be able to specify who starts and how large the initial pile of tokens should be. The player should also be able to start a new game with the program choosing either or both of these values randomly. e. Views do not actually need to belong to a graphical user interface. Write a class named NimLogger that implements IView. Modify the Nim program to use NimLogger to write the state of the game after each move to a file. (Hints: You should not extend JPanel or include any classes from the javax.swing or java.awt packages. Create the NimLogger object in the main method.) f. Modify the model and the view so users may remove up to half of the remaining tokens in each turn. Start the game with a random pile of 20 to 30 tokens. The existing views with three buttons each are inappropriate. Design a new view. g. Modify the PileComponent2 class to show the tokens as a block, three tokens wide. The top row of the block may have less than three tokens. h. The PileComponent2 class shown in Listing 13-23 does not work when a user clicks and drags the mouse upward or leftward. The problem is that the width or the length of the selection rectangle becomes negative, resulting in an empty rectangle. Fix this problem.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
13.11 Problem Set i. The PileComponent2 class shown in Listing 13-23 currently allows the user to select any number of visible tokens, even though the game only allows a maximum of three tokens to be removed. Fix the component so that the selection rectangle is not allowed to enclose more than three tokens. Find the code displayed in Listing 13-21. Write a simple main method to display it in a frame. Observe that it is possible to select several items at once. a. Modify the program so users can select only one item at a time. b. Modify the program to print all of the items that have been selected. c. The JList documentation includes sample code for a class named MyCellRenderer. Read the documentation and then change the program so that each element of the list is displayed using the appropriate color.
721
13.8
Programming Projects
13.9 Write a program to assist users in calculating their target heart rate for an exercise program. You can find many formulas on the Web for calculating the target heart rate. One is based on the users age, resting heart rate, and targeted intensity: intensity * (220 age - restingHR) + restingHR where intensity is a percentage (typically 80 to 90%), age is the users age in years, and restingHR is the users resting heart rate in beats per minute. The model will have mutator methods for intensity, age, and restingHR and accessor methods for those three and the target heart rate. Two possible views are shown in Figure 13-17. a. Write the programs view using JTextField components. b. Write the programs view using JSlider components.
Figure 13-17: Two possible views for a target heart rate calculator.
13.10 Write a program that allows you to display font samples. A proposed user interface is shown in Figure 13-18. The model for this program will have methods such as setFontName, setFontSize, setBold, setItalic, and getFont. The components used in the interface include JComboBox, JCheckBox, JTextArea, and becker.gui.FormLayout.
722
Chapter 13 Graphical User Interfaces 13.11 Explore the documentation for the becker.xtras.nameSurfer package.5 In particular, see the package overview and Figure 13-18 for an example of the interface. a. Write a model named SurferModel. Demonstrate your model working with classes from the nameSurfer package to form a complete program. b. Write a view named SurferView. Demonstrate your view working with classes from the nameSurfer package to form a complete program. (Hint: You will need to implement a custom component to draw the graph.)
Figure 13-18: The font sampler interface.
For use by CS349|SE382 Only
An interface for generating font samples.
An interface for plotting the popularity of names through time.
University of Waterloo, Waterloo, Ontario
13.12 Implement a view to choose a color. See Figure 13-19. It has three JSlider components, one for each of the red, green, and blue parts of a color. Their values range between 0 and 255. Use an empty JPanel to display the current color as the sliders are moved by calling the panels setBackground method. Demonstrate your view with a simple program. The model will have two methods: setColor and getColor. setColor is called when the OK button is pressed, resulting in a second view being updated with the chosen color. 13.13 Use the JEditorPane to implement a simple Web browser like the one shown in Figure 13-19. Users should be able to type a URL into a text field and have it displayed in the JEditorPane. Your browser should also correctly follow links to display a new page. The JEditorPane may not be editable for links to work. The model for the browser will be the current URL to display. Enhancements, below, may require adding a history list and other features to the model. a. Add scroll bars to the JEditorPane that show only if needed. b. Add a toolbar with forward, back, and home buttons. c. Use a JComboBox for entering URLs. Add URLs the user has typed to the JComboBox for easier selection in the future.
5
The original idea for this problem is attributed to Nick Parlante at Stanford University.
13.11 Problem Set
723
Figure 13-19: Sample interfaces for a color chooser and a Web browser.
A simple color chooser.
A simple Web browser.
13.14 Implement the game of Tic-Tac-Toe for two users. See Figure 13-20. Search the Web for the rules if you are unfamiliar with the game. Use a button for each of the nine squares to gather input from the users. Disable the buttons and change their labels as they are played. When the mouse is moved over an unplayed square, show either X or O, depending on whose turn it is. Announce the winner with a dialog box and start a new game.
Figure 13-20: Sample interfaces for a game and an animation.
A Tic-tac-toe game.
An animated bouncing ball.
13.15 Write a program that displays a bouncing ball and allows for its speed to be changed and the size of the box it bounces in to be changed. See Figure 13-20. Hints: Read the documentation for the javax.swing.Timer class. An appropriate delay is 1000/30. There are several classes named Timer; be sure to read the right one. Write a BallModel class with methods such as getBallBounds and setBoxBounds. The java.awt.Rectangle class is convenient for maintaining size and position information for both the ball and the box. The BallModel will also contain an instance of Timer, updating the position of the ball every time it ticks.
724
Chapter 13 Graphical User Interfaces The BallView class should contain a custom component to draw the ball. It will need a controller implementing ComponentListener to resize the models box when the component is resized. The BallView class should also contain an instance of JSlider to adjust the speed of the bouncing ball. 13.16 Implement a model for a right triangle. It will have two methods to set the base and the height but will calculate the length of the hypotenuse using the Pythagorean Theorem (a2 + b2 = c2). It will also have three methods to get the length of each side. The length of the base and the height must be between 1 and 100, inclusive. Figure 13-21 shows several different views of the model. a. Implement a view using JTextField components. b. Implement a view using JSlider components. c. Implement a view using a JButton to increment the length of the base and another to decrement it. Similarly for the height. d. Implement a view using JSpinner to adjust the base and height. e. Implement a view using JCombobox or JList that allows the user to select one of several standard triangle sizes. f. Implement a custom component that draws a picture of the triangle. Set the size of the triangle using one of the other views. g. Implement a custom component that draws a picture of the triangle. Add a controller for the mouse that detects clicks on the triangle. When the triangle is clicked, paint handles to show that it is selected. Allow the user to change its size by dragging the handles. h. Implement a view showing several of the above views, other than (e). Be sure that they all display the same information about the triangle model!
Figure 13-21: Several views of a triangle model.
For use by CS349|SE382 Only
University of Waterloo, Waterloo, Ontario
Find millions of documents on Course Hero - Study Guides, Lecture Notes, Reference Materials, Practice Exams and more.
Course Hero has millions of course specific materials providing students with the best way to expand
their education.
Below is a small sample set of documents:
W. Alabama - CS - 349
Xlib - C Language X InterfaceX Window System Standard X Version 11, Release 6.7James Gettys Cambridge Research Laboratory Digital Equipment Corporation Robert W. Scheifler Laboratory for Computer Science Massachusetts Institute of Technologywith
UCSB - PSYCH - 111
Psy 111 Basic concepts in BiopsychologyLecture 12: Central motor systemsWebsite: http:/mentor.lscf.ucsb.edu/course/fall/psyc111/Neural Innervation of MuscleMotor neuron pool = all the motor neurons (i.e. units) that innervate a single muscle
Delaware - CHEM - 634
Criegee OzonationFatiadi, A. J. New Applications of Tetracyanoethylene in Organometallic Chemistry. Synthesis 1987, 959. OsO4/K3Fe(CN)6 catalyzed dihydroxylation of alkenes Minato, M.; Yamamoto, K.; Tsuji, J. Osmium tetraoxide catalyzed vicinal hydr
Delaware - CHEM - 634
Chem 634 Problem Set1, Fall 2007 Prof. Foxyour name _1) Outline syntheses. Provide a literature reference for each transformation H O H 2) Write an arrow pushing mechanism OMe Mn(OAc)3 (2 equiv) HOAc O CO2CH3 3) Write an arrow pushing mechanism O
N. Arizona - FOR - 213
United States Department of Agriculture Natural Resources Conservation ServiceSoil TaxonomyA Basic System of Soil Classification for Making and Interpreting Soil SurveysSecond Edition, 1999Soil TaxonomyA Basic System of Soil Classification fo
Binghamton - M - 371
Review for Math 222, Name A. (Maybe 30% of the total points). 1. Complete the following items (10 points): 1. The form of the partial fraction of cients) is 2. 3. udv = uvd dx f (u(x) 1 x3 (x2 +x+1)2 (x2),(no need to solve the coe-=d dud d
Binghamton - M - 222
Math 222-15Group ProjectDue: 03/20/09Sequence of quotients of successive Fibonacci numbers Let {qn } be the sequence of quotients of successive Fibonacci numbers, i.e. qn = n=2 so the rst few terms in the sequence are: 1, 2, 3 , 2 5 , 3 8 , 5 .
Binghamton - M - 222
Math 222-15: Calculus 2Strategy for Integration sin(x) dx 1 cos2(x) x2x dx21.2x cos(2x)dx12.2.x2 cos(2x)dx13.3.2x cos(x2)dx cos( x)dx14.cos(x2)dx4.15. 5. 2x dx 1 + 2x 16. 6. ecos(x) sin(x)dx 17. 7. ex cos(x)dx 18. 8. 2x c
ASU - CSE - 565
Reliability BooksReliability Engineering 1. Reliability Engineering: Fundamentals and Applications, R. Ramakumar, Prentice Hall, 1993, ISBN 0-13-276759-7 2. Reliability Engineering, K. Aggarwal, Kluwer Academic Publishers, Boston, 1993 3. Reliabilit
East Los Angeles College - ATT - 1128
CONSOLIDATED COST STATEMENT (CONTRACTOR'S / ASSOCIATE CONTRACTOR'S VIEW)INFORMATION SOCIETY TECHNOLOGIES V IST-2001-34038 DOT-KOM Participant : Associated to : ITC-irstInterim Accepted - Cost statements TOTAL ACCEPTED COSTS IN NATIONAL CURRENCY pe
University of Florida - DOCS - 4712
LM111, LM211, LM311, LM311Y DIFFERENTIAL COMPARATORS WITH STROBESSLCS007A SEPTEMBER 1973 REVISED FEBRUARY 1992D D D D D DFast Response Times Strobe Capability Maximum Input Bias Current . . . 300 nA Maximum Input Offset Current . . . 70 nA Can
University of Florida - DOCS - 4712
aFEATURES Complete 8-Bit DAC Voltage Output0 V to 2.56 V Internal Precision Band-Gap Reference Single-Supply Operation: +5 V ( 10%) Full Microprocessor Interface Fast: 1 s Voltage Settling to 1/2 LSB Low Power: 75 mW No User Trims Required Guarantee
UPenn - VHM - 802
g y y uayaA(Ad |( !(0&!XEX4d !(0i !G! !Aq!a0!2Aa!dhd4Ad!ai(t0X(!di!d g | x g g | g d y w x y y y w x y y v g t y y y y t u u y 4Q(0Aq!wxy000Ad0ifE9a!idAa!d0(qd(iAQ0sxXA!A0
UPenn - VHM - 802
u {y | q { u | ~ qs } o o mc3m1 pQnAwpn1m!w3m!moQp3Q|D3AzkApA1pApQ13mAo kAAv!3kwp3m!mo1m!p!m3!Anp!D!v!{A3pw|13!1wA o q o y p o q y } } p o
University of Florida - DOCS - 4712
25-Sep-083:38 PMJ-K FF, CountersEEL 3701EEL 3701Digital Switch Debounce Circuit (with SPDT) The S-R latch should be made with NANDs or NORs> S-R latch below is made with a D-FF used as an S-R latch+5V ON OFF D C S R Q Q CLN_IN(H) CLN_IN(
University of Florida - DOCS - 4712
MAX 3000AProgrammable Logic Device FamilyData SheetJune 2003, ver. 3.4Features. Highperformance, lowcost CMOS EEPROMbased programmable logic devices (PLDs) built on a MAX architecture (see Table 1) 3.3-V in-system programmabi
University of Florida - DOCS - 4712
Quartus II Introduction Using VHDL DesignThis tutorial presents an introduction to the Quartus R II CAD system. It gives a general overview of a typical CAD flow for designing circuits that are implemented by using FPGA devices, and shows how this f
University of Florida - DOCS - 4712
University Program UP2 Development KitUser GuideJuly 2003, v3.0IntroductionThe University Program UP2 Development Kit was designed to meet the needs of universities teaching digital logic design with state-of-the-art development tools and pr
Cornell - LAW - 128
The crisis of wage arrearsUnpaid salaries in Africa: An explosive issueThere is a link between wage arrears in Africa and structural adjustment programmes promoted there by international financial institutions. But government policies are also par
CSU Northridge - ET - 62917
Thomas Nagels Brain Bisection and Unity of Consciousness [] the personal, mentalist idea of human beings may resists the sort of coordination with an understanding of human beings as physical systems, that would be necessary to yield anything describ
Berkeley - CS - 152
CS 152 Computer Architecture and Engineering Lecture 26 Synchronization2005-4-26 John Lazzaro(www.cs.berkeley.edu/~lazzaro)TAs: Ted Hong and David Marquardtwww-inst.eecs.berkeley.edu/~cs152/CS 152 L26: Synchronization UC Regents Spring 2005
Berkeley - CS - 152
CS 152 Computer Architecture and Engineering Lecture 27 Mid-Term II Review2005-5-3 John Lazzaro(www.cs.berkeley.edu/~lazzaro)TAs: Ted Hong and David Marquardtwww-inst.eecs.berkeley.edu/~cs152/CS 152 L26: Synchronization UC Regents Spring 200
Virginia Tech - CS - 6204
A Transaction Model for Mobile ComputingSanjay Kumar Madria School of Computer Science University Sains Malaysia 1800 Minden, Penang, Malaysia skm@cs.usm.myAbstractIn this paper, we introduce a prewrite operation before a write operation in a mobi
UPenn - CIS - 555
Secur ity and R eplicationZachar y G. I vesUniver sit y of Pennsylvania CI S 455 / 555 I nt er net and Web Syst emsApr il 21, 2009Recall We D iscussed Some Attack s M essage dr opping Replay M essage for ging M an-in-t he-middle H ow do
Rose-Hulman - EC - 300
EC 300HW6Fall 2000Due Tuesday 10-Oct-2000HW6 - Filter DesignFor this assignment you will design three passive filters. Problem 2 requires that you check the filter you designed in problem 1 by analyzing the circuit. You are urged, but not r
Rose-Hulman - EC - 130
1McBoole Multiple-Output Boolean Logic Minimization ProgramThis very convenient and easy-to-use logic minimization program was written by Michael Dagenais in 1984 as part of his Masters Thesis at McGill University in Montreal, Canada. While Karnau
Rose-Hulman - EC - 300
Name_Rose-Hulman Institute of Technology Electrical and Computer EngineeringEC 300 - Exam No. 1 Thursday, December 19, 1995CLOSED BOOK. Work each problem in the space provided on its sheet. Be sure the work you present is clear so the grader can
Rose-Hulman - EC - 300
Name_Rose-Hulman Institute of Technology Electrical and Computer EngineeringEC 300 - Final Exam Wednesday, February 26, 1996CLOSED BOOK. Work each problem in the space provided on its sheet. Be sure the work you present is clear so the grader ca
Rose-Hulman - EC - 130
Name _ Box _ EC130-02/03 Homework #1 (Switching circuit)Due date: Tues. March 6Spring 20011. Fill in the logic function table for the circuit below. The switches have two states: open and closed. The lamp has two states: off and on.BACB
Rose-Hulman - EC - 130
Name _ Box _Due date: Thur. March 8ECE130-02/03 Homework #2 (logic gate & truth table)Spring 20011. Fill in the truth table and find the logic expression for the circuit below.A B X CA 0 0 0 0 1 1 1 1B 0 0 1 1 0 0 1 1C 0 1 0 1 0 1 0 1
Rose-Hulman - EC - 130
Name _ ECE130-02/031Box _ Due date: Monday March 12 Spring 2001Homework #3 (binary numbers)(Part of Problem 3 on page 19 of Dr. Eccles' book). Convert each of the following unsigned binary numbers to their decimal equivalent.Unsigned Binary 1
Wilfrid Laurier - GLGY - 699
HYDROLOGICAL PROCESSES Hydrol. Process. 21, 2610 2622 (2007) Published online in Wiley InterScience (www.interscience.wiley.com) DOI: 10.1002/hyp.6792A simple heat-conduction method for simulating the frost-table depth in hydrological modelsMasaki
Wilfrid Laurier - GLGY - 699
Computer Note/A Visual Basic Spreadsheet Macro for Recession Curve Analysis by Kristijan Posavec1, Andrea Bacani2, and Zoran Nakic2AbstractA Visual Basic program for an Excel spreadsheet was written to construct a master recession curve (MRC),
Wilfrid Laurier - GLGY - 699
Wilfrid Laurier - GLGY - 699
WATER RESOURCES RESEARCH, VOL. 36, NO. 4, PAGES 1069 1077, APRIL 2000Eddy covariance measurements of evaporation from Great Slave Lake, Northwest Territories, CanadaPeter D. Blanken,1 Wayne R. Rouse,2 Alistair D. Culf,3 Chris Spence,2,4 L. Dale Bo
Wilfrid Laurier - GLGY - 699
Journal of Hydrology, 111 (1989) 21-29Elsevier Science Publishers B.V., Amsterdam - - Printed in The Netherlands21[41 E V A P O R A T I O N FROM N A T U R A L N O N S A T U R A T E D S U R F A C E SR.J. GRANGER and D.M. GRAYDivision of Hydro
Wilfrid Laurier - GLGY - 699
Journal of Hydrology 9 (1969) 237-258; North-Holland Publishing Co., AmsterdamNot to be reproduced by photoprint or microfilm without written permission from the publisherBLUEPRINT FOR A PHYSICALLY-BASED, DIGITALLY-SIMULATED HYDROLOGIC RESPONSE M
Duke - CPS - 006
What does this position entail?Do you want to build quantitative models millions of people will use, based on data from the world's largest online laboratory? Are you passionate about formulating relevant questions and producing solutions to initial
Duke - CPS - 006
What does this position entail?Do you want to build quantitative models millions of people will use, based on data from the world's largest online laboratory? Are you passionate about formulating relevant questions and producing solutions to initial
Duke - V - 108
420713351543311011286309320414396295230973262926347560204065331812324387484802347661326585340190263485254274383972392019
Mich Tech - CS - 5461
Report of the National Science Foundation Workshop on Fundamental Research in NetworkingApril 2425, 2003 Airlie House, VirginiaR E P O R T T O T H E N AT I O N A L S C I E N C E F O U N D AT I O N D I R E C T O R AT E F O R C O M P U T E R A N D I
Mich Tech - CS - 5461
Ad-hoc On-Demand Distance Vector RoutingCharles E. Perkins Sun Microsystems Laboratories Advanced Development Group Menlo Park, CA 94025 cperkins@eng.sun.com Elizabeth M. Royer Dept. of Electrical and Computer Engineering University of California, S
Mich Tech - CS - 5461
Geographic Routing without Location InformationAnanth Rao Sylvia Ratnasamy Christos Papadimitriou University of California - Berkeley{ananthar,christos,istoica}@cs.berkeley.eduScott Shenker Ion StoicaABSTRACTFor many years, scalable routing fo
Mich Tech - CS - 5461
Survivable Mobile Wireless Networks: Issues, Challenges, and Research DirectionsJames P.G. Sterbenz, Rajesh Krishnan, Regina Rosales Hain, Alden W. Jackson, David Levin, Ram Ramanathan, and John ZaoBBN Technologies 10 Moulton Street, Cambridge, MA
Mich Tech - CS - 5461
Epidemic Routing for Partially-Connected Ad Hoc NetworksAmin Vahdat and David Becker Department of Computer Science Duke University Durham, NC 27708 (vahdat,becker)@cs.duke.eduAbstract Mobile ad hoc routing protocols allow nodes with wireless adap
Salem State - M - 407
Proof List MAT 407 You should be able to write proofs for each of the following from denitions. That is, many of these theorems (and their proofs) appear in the text. Simply saying this is theorem such-and-such page 47, is insucient. 1. Let P be a p
Rutgers - MATH - 491
The Forty-Sixth Annual William Lowell Putnam Competition Saturday, December 7, 1985(i) (ii), andB3 Let9h s Q 9h 5 Q 9 Q Q 9 Q Q @A3 Let be a real number. For each integer , define a sequence , by the conditionw xv & $
Wentworth - COMP - 232
Wentworth Institute of TechnologyDivision of Professional and Continuing StudiesCOMP232 Section 71 - Computer Programming with Java II - Fall, 2003Homework 1A - LotteryInstructor: Bob Goldstein (617) 912-2592 bobg@vision.eri.harvard.edu http:/us
Sveriges lantbruksuniversitet - ENSC - 835
ENSC 835/CMPT 885: HIGH-PERFORMANCE NETWORKS Final Project Presentation - Spring 2002Evaluation of Different TCP Congestion Control AlgorithmsHilary Zhang Zhengbing Bian {hzhang|zbian}@cs.sfu.caOutlineIntroduction Our Approach Implementation De
Rutgers - MATH - 423
THE 2-DIMENSIONAL LAPLACIAN IN POLAR COORDINATESRecall that with x = r cos and y = r sin as usual, the chain rule (in vector-matrix form) gives f x y f r = r r x f x y f y f cos sin x = f r sin r cos y and therefore (where
Laurentian - CHEM - 200203
Using HyperChem models for molecular symmetry analysis In order to use the provided models, you must first download the files to the computer you are using, or for more permanent storage, download them to your network P drive. In your web-browser, ri
Pittsburgh - UPJ - 14088
Bachelor of Science in Biology (Traditional ) - 120 CreditsGENERAL EDUCATION REQUIREMENTSCOMPETENCY AREASWRITINGEngcmp 0002/0003/0005 Engcmp 0004/0006 Select one of the following options 1 Primary Writing OR 2 Writing Enhanced courses3 3SPEAK
Pittsburgh - UPJ - 14088
Bachelor of Science in Biology (Terrestrial ) - 120 CreditsGENERAL EDUCATION REQUIREMENTSCOMPETENCY AREASWRITINGEngcmp 0002/0003/0005 Engcmp 0004/00063 3SPEAKING (Select one option below) Option A: Any 3 Speaking Enhanced CoursesSelect one
Pittsburgh - UPJ - 14088
Bachelor of Science in Chemistry - 120 CreditsGENERAL EDUCATION REQUIREMENTSCOMPETENCY AREASWRITINGEngcmp 0002/0003/0005 Engcmp 0004/0006 Select one of the following options 1 Primary Writing OR 2 Writing Enhanced courses3 3SPEAKING (Select o
Washington University in St. Louis - CS - 241
CSE 241 Algorithms and Data StructuresSpring Semester, 2009Homework 1January 26, 2009 Due Date: February 9 Practice problems with solutions for similar kinds of problems can be found on the course web page under Homeworks. 1. (15 points) For eac
Washington University in St. Louis - MGST - 1263
PDS_VERSION_ID = PDS3RECORD_TYPE = STREAMOBJECT = TEXT PUBLICATION_DATE = 2002-07-01 NOTE = "Description of the BIN directory contents
Washington University in St. Louis - MGST - 1263
PDS_VERSION_ID = PDS3RECORD_TYPE = STREAMOBJECT = TEXT PUBLICATION_DATE = 1999-05-14 NOTE = "Description of the DOC directory contents
Washington University in St. Louis - MGST - 1263
PDS_VERSION_ID = PDS3RECORD_TYPE = STREAMOBJECT = TEXT PUBLICATION_DATE = 2002-01-01 NOTE = "User documentation for vanilla software."END_OBJECT
Washington University in St. Louis - MGST - 1263
PDS_VERSION_ID = PDS3RECORD_TYPE = STREAMOBJECT = TEXT PUBLICATION_DATE = 2002-01-01 NOTE = "Description of the SRC directory contents
Sveriges lantbruksuniversitet - ENSC - 833
IEEE JOURNAL ON SELECTED AREAS IN COMMUNICATIONS, VOL. 18, NO. 3, MARCH 2000535Performance Analysis of the IEEE 802.11 Distributed Coordination FunctionGiuseppe BianchiAbstractRecently, the IEEE has standardized the 802.11 protocol for Wireless