Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
626
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

Lines 11 and 12 declare an Image reference and an ImageIcon reference, respectively. Class Image is an abstract classthe applet cannot create an object of class Image directly. Rather, we must call a method that causes the applet container to load and return the Image for use in the program. Class Applet (the direct superclass of JApplet) provides method getImage (line 17, in method init) that loads an Image into an applet. This version of getImage takes two argumentsthe location of the image file and the file name of the image. In the first argument, Applet method getDocumentBase returns a URL representing the location of the image on the Internet (or on your computer if the applet was loaded from your computer). Method getdocumentBase returns the location of the HTML file as an object of class URL. The second argument specifies an image file name. The two arguments together specify the unique name and path of the file being loaded (in this case, the file redflowers.png stored in the same directory as the HTML file that invoked the applet). Java supports several image formats, including

Graphics Interchange Format (GIF), Joint Photographic Experts Group (JPEG) and Portable Network Graphics (PNG). File names for these types end with .gif, .jpg (or .jpeg) and .png, respectively.

[Page 981]

Portability Tip 21.1

Class Image is an abstract classas a result, programs cannot instantiate class Image to create objects. To achieve platform independence, the Java implementation on each platform provides its own subclass of Image to store image information.

Line 17 begins loading the image from the local computer (or downloading it from the Internet). When the image is required by the program, it is loaded in a separate thread of execution. Remember that a thread is a parallel activity, and that threads will be discussed in detail in Chapter 23, Multithreading. By using a separate thread to load an image, the program can continue execution while the image loads. [Note: If the requested file is not available, method getImage does not throw an exception. An Image object is returned, but when this Image is displayed using method drawImage, nothing will be displayed.]

Class ImageIcon is not an abstract classa program can create an ImageIcon object. At line 18, in method init creates an ImageIcon object that loads yellowflowers.png. Class ImageIcon provides several constructors that enable programs to initialize ImageIcon objects with images from the local computer or stored on the Internet.

The applet's paint method (lines 2233) displays the images. Line 26 uses Graphics method drawImage to display an Image. Method drawImage accepts four arguments. The first is a reference to the Image object to display (image1). The second and third are the x-and y-coordinates at which to display the image on the appletthe coordinates specify the location of the upper-left corner of the image. The last argument is a reference to an ImageObserveran interface implemented by class Component. Since class JApplet indirectly extends Component, all JApplets are ImageObservers. This argument is important when displaying large images that require a long time to download from the Internet. It is possible that a program will attempt to display the image before it has downloaded completely. The ImageObserver receives notifications as the Image is loaded and updates the image on the screen if the image was not complete when it was displayed. When executing this applet, watch carefully as pieces of the image display while the image loads. [Note: On faster computers, you might not notice this effect.]

[Page 982]

Line 29 uses another version of Graphics method drawImage to output a scaled version of the image. The fourth and fifth arguments specify the width and height of the image for display purposes. Method drawImage scales the image to fit the specified width and height. In this example, the fourth argument indicates that the width of the scaled image should be the width of the applet, and the fifth argument indicates that the height should be 120 pixels less than the height of the applet. The width and height of the applet are determined by calling methods getWidth and getHeight (inherited from class Component).

Line 32 uses ImageIcon method paintIcon to display the image. The method requires four argumentsa reference to the Component on which to display the image, a reference to the Graphics object that will render the image, the x-coordinate of the upper-left corner of the image and the y-coordinate of the upper-left corner of the image.

[Page 982 (continued)]

21.3. Animating a Series of Images

The next example demonstrates animating a series of images that are stored in an array of ImageIcons. The animation presented in Fig. 21.2Fig. 21.3 is implemented using a subclass of JPanel called LogoAnimatorJPanel (Fig. 21.2) that can be attached to an application window or a JApplet. Class LogoAnimator (Fig. 21.3) declares a main method (lines 820 of Fig. 21.3) to execute the animation as an application. Method main declares an instance of class JFrame and attaches a LogoAnimatorJPasnel object to the JFrame to display the animation.

Figure 21.2. Animating a series of images.

(This item is displayed on pages 983 - 984 in the print version)

1 // Fig. 21.2: LogoAnimatorJPanel.java 2 // Animation of a series of images.

3import java.awt.Dimension;

4import java.awt.event.ActionEvent;

5import java.awt.event.ActionListener;

6import java.awt.Graphics;

7import javax.swing.ImageIcon;

8import javax.swing.JPanel;

9import javax.swing.Timer;

11public class LogoAnimatorJPanel extends JPanel

12{

13private final static String IMAGE_NAME = "deitel"; // base image name

14protected ImageIcon images[]; // array of images

15private final int TOTAL_IMAGES = 30; // number of images

16private int currentImage = 0; // current image index

17private final int ANIMATION_DELAY = 50; // millisecond delay

18private int width; // image width

19private int height; // image height

21private Timer animationTimer; // Timer drives animation

23// constructor initializes LogoAnimatorJPanel by loading images

24public LogoAnimatorJPanel()

25{

26images = new ImageIcon[ TOTAL_IMAGES ];

28// load 30 images

29

for (

int

count

= 0; count < images.length; count++ )

30

images[

count ] = new ImageIcon( getClass().getResource(

31

 

"images/"

+ IMAGE_NAME + count

+ ".gif" )

);

32

 

 

 

 

 

 

 

 

33

// this

example

assumes all images have the

same

width and height

34

width

=

images[

0 ].getIconWidth();

// get

icon width

35height = images[ 0 ].getIconHeight(); // get icon height

36} // end LogoAnimatorJPanel constructor

37

38// display current image

39public void paintComponent( Graphics g )

40{

41super.paintComponent( g ); // call superclass paintComponent

43images[ currentImage ].paintIcon( this, g, 0, 0 );

45 // set next image to be drawn only if timer is running

46if ( animationTimer.isRunning() )

47currentImage = ( currentImage + 1 ) % TOTAL_IMAGES;

48} // end method paintComponent

49

50// start animation, or restart if window is redisplayed

51public void startAnimation()

52{

53if ( animationTimer == null )

54{

55currentImage = 0; // display first image

57// create timer

58animationTimer =

59

new Timer( ANIMATION_DELAY, new TimerHandler() );

60

 

61animationTimer.start(); // start timer

62} // end if

63else // animationTimer already exists, restart animation

64{

65if ( ! animationTimer.isRunning() )

66

animationTimer.restart();

67} // end else

68} // end method startAnimation

70// stop animation timer

71public void stopAnimation()

72{

73animationTimer.stop();

74} // end method stopAnimation

76// return minimum size of animation

77public Dimension getMinimumSize()

78{

79return getPreferredSize();

80} // end method getMinimumSize

82// return preferred size of animation

83public Dimension getPreferredSize()

84{

85return new Dimension( width, height );

86} // end method getPreferredSize

87

88// inner class to handle action events from Timer

89private class TimerHandler implements ActionListener

90{

91// respond to Timer's event

92public void actionPerformed( ActionEvent actionEvent )

93{

94repaint(); // repaint animator

95} // end method actionPerformed

96} // end class TimerHandler

97} // end class LogoAnimatorJPanel

Figure 21.3. Displaying animated images on a JFrame.

(This item is displayed on page 985 in the print version)

1

//

Fig. 21.3: LogoAnimator.java

2

//

Animation of a series of images.

3

import javax.swing.JFrame;

4

 

 

5public class LogoAnimator

6{

7

// execute animation in a JFrame

8

public static void main( String args[] )

9{

10LogoAnimatorJPanel animation = new LogoAnimatorJPanel();

12JFrame window = new JFrame( "Animator test" ); // set up window

13window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

14window.add( animation ); // add panel to frame

16window.pack(); // make window just large enough for its GUI

17

window.setVisible( true );

//

display window

18

 

 

 

19

animation.startAnimation();

//

begin animation

20} // end main

21} // end class LogoAnimator

[View full size image]

Class LogoAnimatorJPanel (Fig. 21.2) maintains an array of ImageIcons that are loaded in the constructor (lines 2436). Lines 2931 create each ImageIcon object and store the animation's 30 images in array images. The constructor argument uses string concatenation to assemble the file name from the pieces "images/", IMAGE_NAME, count and ".gif". Each image in the animation is in a file called deitel#

.gif, where # is a value in the range 029 specified by the loop's control variable count. Lines 3435 determine the width and height of the animation from the size of the first image in array imageswe assume that all the images have the same width and height.

After the LogoAnimatorJPanel constructor loads the images, method main of Fig. 21.3 sets up the window in which the animation will appear (lines 1217), and line 19 calls the LogoAnimatorJPanel's startAnimation method (declared at lines 5168 of Fig. 21.2). This method starts the program's animation for the first time or restarts the animation that the program stopped previously. [Note: This method is called when the program is first run, to begin the animation. Although we provide the functionality for this method to restart the animation if it has been stopped, the example does not call the method for this purpose. We have added the functionality, however, should the reader choose to add GUI components that enable the user to start and stop the animation.] For example, to make an animation "browser friendly" in an applet, the animation should stop when the user switches Web pages. If the user returns to the Web page with the animation, method startAnimation can be called to restart the animation. The animation is driven by an instance of class Timer (from package

javax.swing). A Timer generates ActionEvents at a fixed interval in milliseconds (normally specified as an argument to the Timer's constructor) and notifies all its ActionListeners each time an ActionEvent occurs. Line 53 determines whether the Timer reference animationTimer is null. If it is, method startAnimation is being called for the first time, and a Timer needs to be created so that the animation can begin. Line 55 sets currentImage to 0, which indicates that the animation should begin with the image in the first element of array images. Lines 5859 assign a new Timer object to animationTimer. The Timer constructor receives two argumentsthe delay in milliseconds (ANIMATION_DELAY is 50, as specified in line 17) and the ActionListener that will respond to the Timer's ActionEvents. For the second argument, an object of class TimerHandler is created. This class, which implements ActionListener, is declared in lines 8996. Line 61 starts the Timer object. Once started, animationTimer will generate an ActionEvent every 50 milliseconds. Each time an ActionEvent is generated, the Timer's event handler actionPerformed (lines 9295) is called. Line 94 calls

LogoAnimatorJPanel's repaint method to schedule a call to LogoAnimatorJPanel's paintComponent method (lines 3948). Remember that any subclass of JComponent that draws should do so in its paintComponent method. Recall from Chapter 11 that the first statement in any paintComponent method should be a call to the superclass's paintComponent method, to ensure that Swing components are displayed correctly.

[Page 983]

[Page 984]

[Page 985]

If the animation was started earlier, then our Timer has been created and the condition in line 53 will evaluate to false. The program will continue with lines 6566, which restart the animation that the program stopped previously. The if condition at line 65 uses Timer method isRunning to determine whether the Timer is running (i.e., generating events). If it is not running, line 66 calls Timer method restart to indicate that the Timer should start generating events again. Once this occurs, method actionPerformed (the Timer's event handler) is again called at regular intervals. Each time, a call is

made to method repaint (line 94), causing method paintComponent to be called and the next image to be displayed.

[Page 986]

Line 43 paints the ImageIcon stored at element currentImage in the array. Lines 4647 determine whether the animationTimer is running and, if so, prepare for the next image to be displayed by incrementing currentImage by 1. The remainder calculation ensures that the value of currentImage is set to 0 (to repeat the animation sequence) when it is incremented past 29 (the last element index in the array). The if statement ensures that the same image will be displayed if paintComponent is called while the Timer is stopped. This could be useful if a GUI is provided that enables the user to start and stop the animation. For example, if the animation is stopped and the user covers it with another window, then uncovers it, method paintComponent will be called. In this case, we do not want the animation to show the next image (because the animation has been stopped). We simply want the window to display the same image until the animation is restarted.

Method stopAnimation (lines 7174) stops the animation by calling Timer method stop to indicate that the Timer should stop generating events. This prevents actionPerformed from calling repaint to initiate the painting of the next image in the array. [Note: Just as with restarting the animation, this example defines but does not use method stopAnimation. We have provided this method for demonstration purposes, or if the user wishes to modify this example so that it enables the user to stop and restart the animation.]

Software Engineering Observation 21.1

When creating an animation for use in an applet, provide a mechanism for disabling the animation when the user browses a new Web page different from the one on which the animation applet resides.

Remember that by extending class JPanel, we are creating a new GUI component. Thus, we must ensure that our new component works like other components for layout purposes. Layout managers often use a GUI component's getPreferredSize method (inherited from class java.awt.Component) to determine the preferred width and height of the component when laying it out as part of a GUI. If a new component has a preferred width and height, it should override method getPreferredSize (lines 8386) to return that width and height as an object of class Dimension (package java.awt). The Dimension class represents the width and height of a GUI component. In this example, the images are 160 pixels wide and 80 pixels tall, so method getPreferredSize returns a Dimension object containing the numbers 160 and 80 (determined at lines 3435).

Look-and-Feel Observation 21.1

The default size of a JPanel object is 10 pixels wide and 10 pixels tall.

Look-and-Feel Observation 21.2

When subclassing JPanel (or any other JComponent), override method getPreferredSize if the new component is to have a specific preferred width and height.

[Page 987]

Lines 7780 override method getMinimumSize. This method determines the minimum width and height of the component. As with method getPreferredSize, new components should override method getMinimumSize (also inherited from class Component). Method getMinimumSize simply calls getPreferredSize (a common programming practice) to indicate that the minimum size and preferred size are the same. Some layout managers ignore the dimensions specified by these methods. For example, a BorderLayout's NORTH and SOUTH regions use only the component's preferred height.

Look-and-Feel Observation 21.3

If a new GUI component has a minimum width and height (i.e., smaller dimensions would render the component ineffective on the display), override method getMinimumSize to return the minimum width and height as an instance of class Dimension.

Look-and-Feel Observation 21.4

For many GUI components, method getMinimumSize is implemented to return the result of a call to the component's getPreferredSize method.

[Page 987 (continued)]

21.4. Image Maps

Image maps are commonly used to create interactive Web pages. An image map is an image with hot areas that the user can click to accomplish a task, such as loading a different Web page into a browser. When the user positions the mouse pointer over a hot area, normally a descriptive message appears in the status area of the browser or in a tool tip.

Figure 21.4 loads an image containing several of the programming tip icons used in this book. The program allows the user to position the mouse pointer over an icon to display a descriptive message associated with it. Event handler mouseMoved (lines 3943) takes the mouse coordinates and passes them to method translateLocation (lines 5869). Method translateLocation tests the coordinates to determine the icon over which the mouse was positioned when the mouseMoved event occurredthe method then returns a message indicating what the icon represents. This message is displayed in the applet container's status bar using method showStatus of class Applet.

Figure 21.4. Image map.

(This item is displayed on pages 988 - 990 in the print version)

1// Fig. 21.4: ImageMap.java

2// Demonstrating an image map.

3import java.awt.event.MouseAdapter;

4import java.awt.event.MouseEvent;

5import java.awt.event.MouseMotionAdapter;

6import java.awt.Graphics;

7import javax.swing.ImageIcon;

8import javax.swing.JApplet;

9

10 public class ImageMap extends JApplet

11{

12private ImageIcon mapImage;

14private static final String captions[] = { "Common Programming Error",

15"Good Programming Practice", "Graphical User Interface Tip",

16"Performance Tip", "Portability Tip",

17"Software Engineering Observation", "Error-Prevention Tip" };

19// sets up mouse listeners

20public void init()

21{

22addMouseListener(

24new MouseAdapter() // anonymous inner class

25{

26// indicate when mouse pointer exits applet area

27public void mouseExited( MouseEvent event )

28{

29

showStatus( "Pointer outside applet" );

30} // end method mouseExited

31} // end anonymous inner class

32); // end call to addMouseListener

34

addMouseMotionListener(

35

 

36new MouseMotionAdapter() // anonymous inner class

37{

38// determine icon over which mouse appears

39public void mouseMoved( MouseEvent event )

40{

41

showStatus( translateLocation(

42

event.getX(), event.getY() ) );

43} // end method mouseMoved

44} // end anonymous inner class

45); // end call to addMouseMotionListener

47mapImage = new ImageIcon( "icons.png" ); // get image

48} // end method init

50// display mapImage

51public void paint( Graphics g )

52{

53super .paint( g );

54mapImage.paintIcon( this, g, 0, 0 );

55} // end method paint

56

57// return tip caption based on mouse coordinates

58public String translateLocation( int x, int y )

59{

60// if coordinates outside image, return immediately

61if ( x >= mapImage.getIconWidth() || y >= mapImage.getIconHeight() )

62return "";

63

64// determine icon number (0 - 6)

65double iconWidth = ( double ) mapImage.getIconWidth() / 7.0;

66

int iconNumber = ( int )( ( double ) x / iconWidth );

67

 

68return captions[ iconNumber ]; // return appropriate icon caption

69} // end method translateLocation

70} // end class ImageMap

[View full size image]

Clicking in the applet of Fig. 21.4 will not cause any action. In Chapter 24, Networking, we discuss the techniques required to load another Web page into a browser via URLs and the AppletContext interface. Using those techniques, this applet could associate each icon with a URL that the browser would display when the user clicks the icon.