GUI Programming

240
GUI Programming Java

Transcript of GUI Programming

GUIProgrammingJava

V. Dinesh Ad It Services

ContentsChapter -1 : Introduction to GUI Programming1. Introduction 2. Java Foundation Classes [JFC] a. Awt b. Swing c. Pluggable Look-and-Feel d. Accessibility API e. Java 2D f. Internationalization 3. GUI Programming in Java a. Containers b. Layouts c. Components d. Event Handling e. Applications Vs. Applets

Chapter -2 : Applets & Graphics4. Applets a. Creating an Applet b. Life Cycle & Life Cycle Methods c. Running an Applet d. Passing Parameters e. Images & Sounds f. Security Policies /Attributes/Permissions 5. The Graphics Class & Methods

Chapter -3 : AWT Programming6. AWT a. All about Containers Applet, Window, Frame & Panel b. The Layout Manager & Layouts Flow Layout, Card Layout, Grid Layout, GridBag Layout, Border Layout c. AWT Components Button, TextField, CheckBox, RadioButton, TextArea, ListBox, ComboBox d. MenuBar, Menu, MenuItem 7. Event handling mechanisms for various components and Containers Listeners, Adapter classes, Anonymous inner classes

Chapter -4 : Swing Programming8. Introduction to Swing 9. MVC architecture implementation in Swings , AWT Vs. Swing 10. Frames, Panels and Borders 11. Layout Managers 12. Labels and Buttons 13. Tabbed Pane/Scrolling Pane/Split Panes 14. Combo/List boxes and Spinners 15. Text Components 16. Menus/Toolbars and Actions 17. Progress Bar, Slider and Scroll Bar 18. Dialogs 19. Layered Panes and Custom MDI 20. Desktop and Internal Frames 21. Trees / Tables 22. Pluggable look and feel

Chapter -1Introduction to GUI Programming

IntroductionWhy GUI Programming ? In early days programmers used Character User Interface to develop applications. The users of the program need to remember many commands to work with that particular application. It was very difficult and time consuming. After the invention of Object Oriented Programming, programmers started to develop applications based on Graphical User Interface [GUI]. The users need not remember commands. Visual images are very easy to identify and use. Graphical User Interface applications are very easy and convenient to work with.

Java Foundation Classes [JFC]Java provides JFC, in short for Java Foundation Classes, which encompass a group of features for building graphical user interfaces (GUIs) and adding rich graphics functionality and interactivity to Java applications. It is defined as containing the features shown in the tab le below. Features of the Java Foundation Classes Feature Description AWT A set of heavy weight components and containers A series of light weight components, includes everything from Swing GUI buttons to split panes to tables. Many components are capable of Components sorting, printing, and drag and drop, to name a few of the supported features. The look and feel of Swing applications is pluggable, allowing a choice of look and feel. For example, the same program can use Pluggable Look-and- either the Java or the Windows look and feel. Additionally, the Java Feel Support platform supports the GTK+ look and feel, which makes hundreds of existing look and feels available to Swing programs. Many more look-and-feel packages are available from various sources. Enables assistive technologies, such as screen readers and Braille Accessibility API displays, to get information from the user interface. Enables developers to easily incorporate high-quality 2D graphics, text, and images in applications and applets. Java 2D includes Java 2D API extensive APIs for generating and sending high-quality output to printing devices. Allows developers to build applications that can interact with users worldwide in their own languages and cultural conventions. Internationalization With the input method framework developers can build applications that accept text in languages that use thousands of different characters, such as Japanese, Chinese, or Korean.

The Java Foundation Classes consist of following major parts: 1. 2. 3. 4. 5. 6. AWT Swing Pluggable Look-and-Feel Support Accessibility Java 2D Internationalization

Java 2D has become an integral part of AWT, Swing is built on top of AWT, and Accessibility support is built into Swing. Thus, AWT is at the core of JFC, which in turn makes it one of the most important libraries in Java 2. AWT (the Abstract Window Toolkit) AWT is the part of Java designed for creating user interfaces and painting graphics and images. It is a set of classes intended to provide everything a developer requires in order to create a graphical interface for any Java applet or application. Most AWT components are derived from the java.awt.Component class. Swing Swing is a large set of components ranging from the very simple, such as labels, to the very complex, such as tables, trees, and styled text documents. Almost all Swing components are derived from a single parent called JComponent which extends the AWT Container class. Thus, Swing is best described as a layer on top of AWT rather than a replacement for it. Pluggable Look-and-Feel Support The look and feel of Swing applications is pluggable, allowing a c hoice of look and feel. For example, the same program can use either the Java or the Windows look and feel. Additionally, the Java platform supports the GTK+ look and feel, which makes hundreds of existing look and feels available to Swing programs. Many m ore look-and-feel packages are available from various sources. Accessibility API Enables assistive technologies, such as screen readers and Braille displays, to get information from the user interface. Java 2D API Enables developers to easily incorporate high-quality 2D graphics, text, and images in applications and applets. Java 2D includes extensive APIs for generating and sending high-quality output to printing devices. Internationalization Allows developers to build applications that can interact with users worldwide in their own languages and cultural conventions. With the input method framework developers can build applications that accept text in languages that use thousands of different characters, such as Japanese, Chinese, or Korean.

GUI Programming in JavaJava library provides number of class and interfaces to develop GUI applications. Using AWT and swing we can develop GUI applications. While developing GUI application using AWT or swing we need to follow the below steps. 1. 2. 3. 4. 5. Create a container Define a layout Create components and add components to container Define event methods Register event methods to your components

AWT and Swing provides wide variety of components to build GUI applications. These components or categorized as follows.. 1. Containers 2. Layouts 3. Components Containers Containers(Frames, Dialogs, Windows and Panels) can contain components and are themselves components, thus can be added to Containers. Containers usually handle events that occurred to the Components, although nothing prevents you from handling events in the component. In short all classes derived from Container can be one. Layouts How Components are "laid out" within a Container is described by the LayoutManager class. Since the LayoutManager class is abstract, we can not use it directly. You must sub-class it and provide your own functionality or use a derived class of LayoutManager(i.e BorderLayout, CardLayout, GridLayout, etc) already created for you. Components Components are generally the stuff that the user interacts with. You'll need to display Windows and Buttons. You'll want Lists within Windows. You'll want the user to enter some text/input. You'll want easy access to features and functions. Components will do that for you. Components are Buttons, TextAreas, Scrollbars, etc. in other words the visible UI controls that the user interacts with, all of which have been added to a Container. Anything that is derived from the class Component can be one.

Applications V. Applets In the early days of Java, one of the critical advantages that Java applets had over Java applications was that applets could be easily deployed over the web while Java applications required a more cumbersome installation process. Additionally, since applets are downloaded from the internet, by default they have to run in a restricted security environment, called the "sandbox", to ensure they don't perform any destructive operations on the user's computer, such as reading/writing to the file system. However, the introduction of Java Web Start has made it possible for Java applications to also be easily deployed over the web, as well as run in a secure environment. This means that the predominant difference between a Java applet and a Java application is that an applet runs in the context of a web browser, being typically embedded within an html page, while a Java application runs standalone, outside the browser. Thus, applets are particularly well suited for providing functions in a web page which require more interactivity or animation than HTML can provide, such as a graphical game, complex editing, or interactive data visualization. The end user is able to access the functionality without leaving the browser.y

Appleto o o o o

Programs that are downloaded from the Web and executed inside of a browser Cannot read or write to local file system Cannot communicate with any server other than the one that the applet was downloaded from Cannot run any program on user's system Cannot load programs native to the local platform

y

Application o Stand alone Java programs that do not require a Web browser to run o They are more general purpose programs o They do not have security restrictions that applets have o They are typically executed using the command line JVM (java)

Chapter -2Applets and Graphics

AppletsAn applet is a special kind of Java program that a browser enabled with Java technology can download from the internet and run. An applet is typically embedded inside a webpage and runs in the context of the browser. An applet must be a subclass of the java.applet.Applet class, which provides the standard interface between the applet and the browser environment. Swing provides a special subclass of Applet, called javax.swing.JApplet, which should be used for all applets that use Swing components to construct their GUIs. By calling certain methods, a browser manages an applet life cycle, if an applet is loaded in a web page. Creating an Applet 1. 2. 3. 4. 5. The applet class is declared public . The applet class descends from Applet/JApplet. The applet version has no main method. The application constructor is replaced in the applet by start and init methods. GUI components are added directly to the Applet.

A Sample Applet which prints Welcome Messegeimport java.awt.applet.Applet; import java.awt.Graphics; public class Hello extends Applet { public void paint(Graphics g) { g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); g.drawString("Hello Friend!", 5, 15); } }

Life Cycle of an Applet Basically, there are four methods in the Applet class on which any applet is built. init: This method is intended for whatever initialization is needed for your applet. It is called after the param attributes of the applet tag. start: This method is automatically called after init method. It is also called whenever user returns to the page containing the applet after visiting other pages. stop: This method is automatically called whenever the user moves away from the page containing applets. You can use this method to stop an animation. destroy: This method is only called when the browser shuts down normally.

Thus, the applet can be initialized once and only once, started and stopped one or more times in its life, and destroyed once and only once. Example :import java.applet.Applet; import java.awt.Graphics; public class Simple extends Applet { StringBuffer buffer; public void init() { buffer = new StringBuffer(); addItem("initializing... "); } public void start() { addItem("starting... "); } public void stop() { addItem("stopping... "); } public void destroy() { addItem("preparing for unloading..."); } private void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint(Graphics g) { //Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); //Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } }

Running an Applet To run an Applet we need to follow below guide lines. 1. 2. 3. 4. Create a html page. Embed applet using tag Deploy applet and html page in the web server Open the page in a web browser.

You use the applet tag to deploy applets to a multi-browser environment. Note: The HTML specification states that the applet tag is deprecated, and that you should use the object tag instead. However, the specification is vague about how browsers should implement the object tag to support Java applets, and browser support is currently inconsistent. It is therefore recommended that you continue to use the applet tag as a consistent way to deploy Java applets across browsers on all platforms. Following is an example of the applet tag: Your browser does not support the applet tag. For both Internet Explorer and the Mozilla family of browsers, if Java Plug-in is installed (version 1.3.1_01a or later) then the latest installed version of Java Plug-in is invoked to run the applet. Note: You cannot use the applet tag to automatically download a JRE if one is not installed locally. Passing Parameters Parameters are to applets what command-line arguments are to applications. They allow the user to customize the applet's operation. By defining parameters, you can increase your applet's flexibility, making your applet work in multiple situations without recoding and recompiling it. When implementing parameters, you must answer four questions:y y y y

What should the applet let the user configure? What should the parameters be named? What kind of value should each parameter take? What should the default value of each parameter be?

Applets get the user-defined values of parameters by calling the Applet getParameter method. By implementing the getParameterInfo method, applets provide information that browsers can use to help the user set parameter values. A Sample Tag

Applets use the Applet getParameter method to get user-specified values for applet parameters. The getParameter method is defined as follows: public String getParameter(String name) Your applet might need to convert the string that getParameter returns into another form, such as an integer. The java.lang package provides classes such as Integer that you can use to help with converting strings t o primitive types. Here's an example of converting a parameter's value into an integer: int requestedWidth = 0; ... String windowWidthString = getParameter("WINDOWWIDTH"); if (windowWidthString != null) { try { requestedWidth = Integer.parseInt(windowWidthString); } catch (NumberFormatException e) { //Use default width. } } Note that if the user doesn't specify a value for the WINDOWWIDTH parameter, the above code uses a default value of 0, which the applet interprets as "use the window's natural size." It's important that you supply default values wherever possible. By default, a browser looks for an applet's class and archive files in th e same directory as the HTML file that has the tag. (If the applet's class is in a package, then the browser uses the package name to construct a directory path underneath the HTML file's directory.) Sometimes, however, it's useful to put the applet's files somewhere else. You can use the CODEBASE attribute to tell the browser in which directory the applet's files are located: If aURL is a relative URL, then it's interpreted relative to the HTML document's location. By making aURL an absolute URL, you can load an applet from just about anywhere even from another HTTP server. Playing Sounds The JApplet class in the Java Swing package (javax.swing), and the AudioClip interface in the Java Applet package (java.applet) provide basic support for playing sounds. Currently, the Java API supports only one sound format: 8 bit, -law, 8000 Hz, onechannel, Sun ".au" files. You can create these on a Sun workstation using the audiotool application. You can convert files from other sound formats using an audio format conversion program.

Sound-Related Methods Below are the sound-related Applet methods. The two-argument form of each method takes a base URL, which is usually returned by either getDocumentBase or getCodeBase, and the location of the sound file relative to the base URL. getAudioClip(URL), getAudioClip(URL, String) Return an object that implements the AudioClip interface. play(URL), play(URL, String) Play the AudioClip corresponding to the specified URL. The AudioClip interface defines the following methods: loop : Starts playing the clip repeatedly. play : Plays the clip once. stop : Stops the clip. Works with both looping and one -time sounds. Example Here is an applet called SoundExample that illustrates a few things about sound. The SoundExample applet provides an architecture for loading and playing multiple sounds in an applet. For this reason, it is more complex than necessary. Essentially, the sound loading and playing code boils down to this: AudioClip onceClip, loopClip; onceClip = applet.getAudioClip(getCodeBase(), "bark.au"); loopClip = applet.getAudioClip(getCodeBase(), "train.au"); onceClip.play(); //Play it once. loopClip.loop(); / /Start the sound loop. loopClip.stop(); //Stop the sound loop. Since there's nothing more annoying than an applet that continues to make noise after you've left its page, the SoundExample applet stops playing the continuously looping sound when the user leaves the page, and resumes playing it when the user comes back. It does this by implementing its stop and start methods as follows: public void stop() { //If one-time sound were long, we'd stop it here, too. //looping is a boolean instance v ariable that's initially //false. It's set to true when the "Start sound loop" button //is clicked and to false when the "Stop sound loop" or "Reload //sounds" button is clicked. if (looping) { loopClip.stop(); //Stop the sound l oop. } }

public void start() { if (looping) { loopClip.loop(); //Restart the sound loop. } } The SoundExample applet features three classes:y y

y

A JApplet subclass, SoundExample, that controls the applet's execution. A Hashtable subclass, SoundList, that holds AudioClips. This is overkill for this applet, but if you were to write an applet that used lots of sound files, a class like this would be useful. A Thread subclass, SoundLoader, each instance of which loads an AudioClip in the background. During the applet's initialization, the applet preloads each sound by creating a SoundLoader for it.

Preloading the sounds in a background thread (with SoundLoader) improves the perceived performance by reducing the amount of time the user has to wait to be able to interact with the applet. It does this by reducing the amount of time spent in the init method. If you simply called getAudioClip in the applet's init method, it could take quite a while before getAudioClip returned, meaning that the applet couldn't perform the other statements in its init method, and that the applet's start wouldn't get called. (For this SoundExample applet, a delay in calling the start method doesn't matter.) Another advantage of loading the sounds in a background thread is that it enables the applet to respond appropriately (and immediately) to user input that would normally cause a sound to play, even if that sound hasn't been loaded yet. If you simply use the Applet play method, for example, then the first time the user does something to make the applet play a particular sound, the applet's drawing and event handling are frozen while the sound is loaded. Instead, this applet detects that the sound hasn't been loaded yet and responds appropriately. Security Policies Every browser implements security policies to keep applets from compromising system security. This section describes the security policies that current browsers adhere to. However, the implementation of the security policies differs from browser to browser. Also, security policies are subject to change. For example, if a browser is developed for use only in trusted environments, then its security policies will likely be much more lax than those described here. Current browsers impose the following restrictions on any applet that is loaded over the network:y y y y y y

An applet cannot load libraries or define native methods. It cannot ordinarily read or write files on the host that's executing it. It cannot make network connections except to the host that it came from. It cannot start any program on the host that's executing it. It cannot read certain system properties. Windows that an applet brings up look different than windows that an application brings up.

Each browser has a SecurityManager object that implements its security policies. When a SecurityManager detects a violation, it throws a SecurityException. Your applet can catch this SecurityException and react appropriately. The Graphics Class & Methods Using the Paint Method To draw the applet's representation within a browser page, you use the paint method. For example, the Simple applet defines its onscreen appearance by overriding the paint method: public void paint(Graphics g) { //Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); //Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } Applets inherit the paint method from the Abstract Window Toolkit (AWT) Container class. The Graphics Class Methods The Graphics class is the abstract base class for all graphics contexts that allow an application to draw onto components that are realized on various devices, as well as onto off-screen images. A Graphics object encapsulates state information needed for the basic rendering operations that Java supports. This state information includes the following properties:y y y y y y y y

The Component object on which to draw. A translation origin for rendering and clipping coordinates. The current clip. The current color. The current font. The current logical pixel operation function (XOR or Paint). The current XOR alternation color

clearRect(int x, int y, int width, int height) : Clears the specified rectangle by filling it with the

background color of the current drawing surface.clipRect(int x, int y, int width, int height): Intersects the current clip with the specified

rectangle.

copyArea(int x, int y, int width, int height, int dx, int dy) : Copies an area of the component by a distance specified by dx and dy. create() : Creates a new Graphics object that is a copy of this Graphics object. create(int x, int y, int width, int height) : Creates a new Graphics object based on this Graphics

object, but with a new translation and clip area.dispose() : Disposes of this graphics context and releases any system resources that it is

using.draw3DRect(int x, int y, int width, int height, boolean raised): Draws a 3-D highlighted outline of

the specified rectangle.drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) :

Draws the outline of a circular or elliptical arc covering the specified rectangle.drawBytes(byte[] data, int offset, int length, int x, int y) : Draws the text given by the specified

byte array, using this graphics context's current font and color.drawChars(char[] data, int offset, int length, int x, int y) : Draws the text given by the specified

character array, using this graphics context's current font and color.drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer):

Draws as much of the specified image as is currently available.drawImage(Image img, int x, int y, ImageObserver observer) : Draws as much of the specified

image as is currently available.drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) :

Draws as much of the specified image as has already been scaled to fit inside the specified rectangle.drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) : Draws as much of

the specified image as has already been scaled to fit inside the specified rectangle.drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer): Draws as much of the specified area of the specified image as is

currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) : Draws as much of the specified area of the specified image as is

currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.drawLine(int x1, int y1, int x2, int y2) : Draws a line, using the current color, between the points (x1, y1) and (x2, y2) in this graphics context's coordinate system. drawOval(int x, int y, int width, int height): Draws the outline of an oval. drawPolygon(int[] xPoints, int[] yPoints, int nPoints): Draws a closed polygon defined by arrays

of x and y coordinates.drawPolygon(Polygon p) : Draws the outline of a polygon defined by the specified Polygon

object.drawPolyline(int[] xPoints, int[] yPoints, int nPoints):Draws a sequence of connected lines

defined by arrays of x and y coordinates.

drawRect(int x, int y, int width, int height) : Draws the outline of the specified rectangle. drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) : Draws an outlined

round-cornered rectangle using this graphics context's current color.drawString(AttributedCharacterIterator iterator, int x, int y): Renders the text of the specified iterator applying its attributes in accordance with the specification of the TextAttribute

class.drawString(String str, int x, int y) : Draws the text given by the specified string, using this

graphics context's current font and color.fill3DRect(int x, int y, int width, int height, boolean raised): Paints a 3-D highlighted rectangle

filled with the current color.fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) :

Fills a circular or elliptical arc covering the specified rectangle.fillOval(int x, int y, int width, int height) : Fills an oval bounded by the specified rectangle with

the current color.fillPolygon(int[] xPoints, int[] yPoints, int nPoints): Fills a closed polygon defined by arrays of x

and y coordinates.fillPolygon(Polygon p) : Fills the polygon defined by the specified Polygon object with the

graphics context's current color.fillRect(int x, int y, int width, int height): Fills the specified rectangle. fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) : Fills the specified

rounded corner rectangle with the current color.finalize() : Disposes of this graphics context once it is no longer referenced. getClip() : Gets the current clipping area. getClipBounds(): Returns the bounding rectangle of the current clipping area. getClipBounds(Rectangle r): Returns the bounding rectangle of the current clipping area. getClipRect() : Deprecated. As of JDK version 1.1, replaced by getClipBounds(). getColor() : Gets this graphics context's current color. getFont() : Gets the current font. getFontMetrics(): Gets the font metrics of the current font. getFontMetrics(Font f):Gets the font metrics for the specified font. hitClip(int x, int y, int width, int height) : Returns true if the specified rectangular area might

intersect the current clipping area.setClip(int x, int y, int width, int height) : Sets the current clip to the rectangle specified by the

given coordinates.setClip(Shape clip) : Sets the current clipping area to an arbitrary clip shape. setColor(Color c) :Sets this graphics context's current color to the specified color. setFont(Font font): Sets this graphics context's font to the specified font. setPaintMode() : Sets the paint mode of this graphics context to overwrite the destination

with this graphics context's current color.setXORMode(Color c1): Sets the paint mode of this graphics context to alternate between

this graphics context's current color and the new specified color.toString() : Returns a String object representing this Graphics object's value. translate(int x, int y): Translates the origin of the graphics context to the point ( x, y) in the

current coordinate system. Handling Events Applets inherit a group of event-handling methods from the Container class. The Container class defines several methods, such as processKeyEvent and processMouseEvent, for handling particular types of events, and then one catch-all method called processEvent. To react to an event, an applet must override the appropriate event-specific method. For example, the following program, SimpleClick, implements a MouseListener and overrides the mouseClicked method. /* * Java(TM) SE 6 version. */ import java.awt.event.MouseListener; import java.awt.event.MouseEvent; import java.applet.Applet; import java.awt.Graphics; //No need to extend JApplet, since we don't add any components; //we just paint. public class SimpleClick extends Applet implements MouseListener { StringBuffer buffer; public void init() { addMouseListener(this); buffer = new StringBuffer(); addItem("initializing... "); } public void start() { addItem("starting... "); } public void stop() { addItem("stopping... ");

} public void destroy() { addItem("preparing for unloading..."); } void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint(Graphics g) { //Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); //Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } //The following empty methods could be removed //by implementing a MouseAdapter (usually done //using an inner class). public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } public void mousePressed(MouseEvent event) { } public void mouseReleased(MouseEvent event) { } public void mouseClicked(MouseEvent event) { addItem("click!... "); } } Sending Messages to Other Applets Applets can find other applets and send messages to them, with the following security restrictionsy y y

Many browsers require that the applets originate from the same server. Many browsers further require that the applets originate from the same directory on the server (the same code base). The Java API requires that the applets be running on the same page, in the same browser window.

Note: Some browsers let applets invoke methods on other applets even applets on different pages in the same browser as long as all of the applets come from the same code base. This method of interapplet communication isn't supported by the Java API, so it's possible that it will not be suppo rted by all browsers. An applet can find another applet either by looking it up by name (using the AppletContext getApplet method) or by finding all the applets on the page (using the AppletContext getApplets method). Both methods, if successful, give the caller one or more Applet objects. Once the caller finds an Applet object, the caller can invoke methods on the object. Finding an Applet by Name: The getApplet Method The getApplet method looks through all of the applets on the current page to see if one of them has the specified name. If so, getApplet returns the applet's Applet object. By default, an applet has no name. For an applet to have a name, one must be specified in the HTML code that adds the applet to a page. You can specify an applet's name in two ways: By specifying a NAME attribute within the applet's tag. For example: ... By specifying a NAME parameter with a tag. For example: ... Browser Note: Although at least one browser enabled with Java technology conducts a case-sensitive search, the expected behavior is for the getApplet method to perform a case-insensitive search. For example, getApplet("old pal") and getApplet("OLD PAL") should both find an applet named "Old Pal".

Here's the whole Sender program. The code it uses to look up and communicate with the Receiver is listed below. Code that you can use without change in your own applet is in bold font. Applet receiver = null;

String receiverName = nameField.getText(); //Get name to search for. receiver = getAppletContext().getApplet(receiverName); The Sender goes on to make sure that the Receiver was found and that it's an instance of the correct class (Receiver). If all goes well, the Sender sends a message to the Receiver. (Here's the Receiver program.) if (receiver != null) { //Use the instanceof operator to make sure the applet //we found is a Receiver object. if (!(receiver instanceof Receiver)) { status.appendText("Found applet named " + receiverName + ", " + "but it's not a Receiver object.\n"); } else { status.appendText("Found applet named " + receiverName + ".\n" + " Sending message to it.\n"); //Cast the receiver to be a Receiver object //(instead of just an Applet object) so that the //compiler will let us call a Receiver method. ((Receiver)receiver).processRequestFrom(myName); } }... From an applet's point of view, its name is stored in a parameter named NAME. It can get the value of the parameter using the Applet getParameter method. For example, Sender gets its own name with the following code: myName = getParameter("NAME"); The example applets in this page perform one-way communication from the Sender to the Receiver. If you want your receiver to be able to send messages to the sender, then you just need to have the sender give a reference to itself (this) to the receiver. For example: ((Receiver)receiver).startCommunicating(this); Finding All the Applets on a Page: The getApplets Method The getApplets method returns a list (an Enumeration, to be precise) of all the applets on the page. For security reasons, many browsers and applet viewers implement getApplets so that it returns only those applets that originated from the same host as the applet calling getApplets. Here's an applet that simply lists all the applets it can find on this page: Below are the relevant parts of the method that calls getApplets. (Here's the whole program.) public void printApplets() { //Enumeration will contain all applets on this page (including

//this one) that we can send messages to. Enumeration e = getAppletContext().getApplets(); ... while (e.hasMoreElements()) { Applet applet = (Applet)e.nextElement(); String info = ((Applet)applet).getAppletInfo(); if (info != null) { textArea.appendText("- " + info + "\n"); } else { textArea.appendText("- " + applet.getClass().getName() + "\n"); } } ... } Threads in Applets Every applet can run in multiple threads. The applet's GUI is created on the eventdispatching thread. The threads that the major milestone methods init, start, stop, and destroy are called from depends on the application that's running the applet. But no application ever calls them from the event handling thread. Many browsers allocate a thread for each applet on a page, using that thread for all calls to the applet's major milestone methods. Some browsers allocate a thread group for each applet, so that it's easy to kill all the threads that belong to a particular applet. In any case, you're guaranteed that every thread that any of an applet's major milestone methods creates belongs to the same thread group. Below is a PrintThread applet. PrintThread is a modified version of SimpleApplet that prints the thread and thread group that its init, start, stop, destroy, and update methods are called from. Here's the code for the PrintThread example. As usual, to see the output for the methods such as destroy that are called during unloading, you need to look at the standard output. For standard output for an applet run in a browser, open the Java Console from the browser's Tools menu. See Displaying Diagnostics to the Standard Output and Error Streams for information about the standard output stream. So why would an applet need to create and use its own threads? Imagine an applet that performs some time-consuming initialization loading images, for example in its init method. The thread that invokes init can not do anything else until init returns. In some browsers, this might mean that the browser can't display the applet or anything after it until the applet has finished initializing itself. So if the applet is at the top of the page, for example, then nothing would appear on the page until the applet has finished initializing itself.

Even in browsers that create a separate thread for each applet, it makes sense to put any time-consuming tasks into an applet-created thread, so that the applet can perform other tasks while it waits for the time-consuming ones to be completed. If an applet performs a time-consuming task, it should create and use its own thread to perform that task. Applets typically perform two kinds of time-consuming tasks: tasks that they perform once, and tasks that they perform repeatedly. Examples The first applet, AnimatorApplet, shows how to use a thread to perform repeated tasks. The second applet discusses, SoundExample, shows how to use threads for one-time initialization tasks. Using a Thread to Perform Repeated Tasks An applet that performs the same task over and over again typically should have a thread with a while (or do...while) loop that performs the task. A typical example is an applet that performs timed animation, such as a movie player or a game. Animation applets need a thread that requests repaints at regular intervals. Another example is an applet that reads data supplied by a server-side application. Applets typically create threads for repetitive tasks in the applet start method. Creating the thread there makes it easy for the applet to stop the thread when the user leaves the page. All you need to do is implement the stop method so that it stops the applet's thread. When the user returns to the applet's page, the start method is called again, and the applet can again create a thread to perform the repetitive task. Below is AnimatorApplet's implementation of the start and stop methods. public void start() { if (frozen) { //Do nothing. The user has requested that we //stop changing the image. } else { //Start animating! if (animatorThread == null) { animatorThread = new Thread(this); } animatorThread.start(); } } public void stop() { animatorThread = null; }

The this in new Thread(this) indicates that the applet provides the body of the thread. It does so by implementing the java.lang.Runnable interface, which requires the applet to provide a run method that forms the body of the thread. We'll discuss AnimatorApplet's run method more a little later. Notice that nowhere in the AnimatorApplet class is the Thread stop method called. This is because calling the Thread stop method is like clubbing the thread over the head. It's a drastic way to get the thread to stop what it's doing. Instead, you can write the thread's run method in such a way that the thread will gracefully exit when you tap it on the shoulder. This shoulder tap comes in the form of setting to null an instance variable of type Thread. In AnimatorApplet, this instance variable is called animatorThread. The start method sets it to refer to the newly created Thread object. When the applet needs to kill the thread, it sets animatorThread to null. This kills the thread not by making it be garbage collected it can't be garbage collected while it's runnable but because at the top of its loop, the thread checks animatorThread, continuing or exiting depending on the value of animatorThread. Here's the relevant code: public void run() { ... while (Thread.currentThread() == animatorThread) { ...//Display a frame of animation and then sleep. } } If animatorThread refers to the same thread as the currently executing thread, the thread continues executing. If, on the other hand, animatorThread is null, the thread exits. If animatorThread refers to another thread, then a race condition has occurred: start has been called so soon after stop (or this thread has taken such a long time in its loop) that start has created another thread before this thread reached the top of its while loop. Whatever the cause of the race condition, this thread should exit. Using a Thread to Perform One-Time Initialization If your applet needs to perform some initialization task that can take a while, you should consider ways of performing the initialization in a thread. For example, anything that requires making a network connection should generally be done in a background thread. Fortunately, GIF, PNG, and JPEG image loading is automatically done in the background using threads that you don't need to worry about. Sound loading, unfortunately, is not guaranteed to be done in the background. In current implementations, the Applet getAudioClip methods don't return until they've loaded all the audio data. As a result, if you want to preload sounds, you might want to create one or more threads to do so. Using a thread to perform a one-time initialization task for an applet is a variation of the classic producer/consumer scenario. The thread that performs the task is the producer,

and the applet is the consumer. Synchronization discusses how to use Java threads in a producer/consumer scenario. SoundExample adheres closely to the model presented in Synchronizing Threads. Like the Synchronizing Threads example, SoundExample features three classes:y y

y

The producer: SoundLoader, a Thread subclass. The consumer: SoundExample, an Applet subclass. Unlike the Synchronizing Threads consumer example, SoundExample is not a Thread; it doesn't even implement the Runnable interface. However, the SoundExample instance methods are executed by at least two threads, depending on the application that executes the SoundExample applet. The storage object: SoundList, a Hashtable subclass. Unlike CubbyHole in the Synchronizing Threads example, SoundList can return null values if the sound data hasn't been stored yet. This makes sense for this applet because it needs to be able to react immediately to a user request to play the sound, even if the sound hasn't been loaded yet.

Chapter -3AWT Programming

Graphical User Interfaces The Java programming language provides a class library called the Abstract Window Toolkit (AWT) that contains a number of common graphical widgets. You can add these widgets to your display area and position them with a layout manager. AWT Basics All graphical user interface objects stem from a common superclass, Component. To create a Graphical User Interface (GUI), you add components to a Container object. Because a Container is also a Component, containers may be nested arbitrarily. Most often, you will use a Panel when creating nested GUIs. Each AWT component uses native code to display itself on your screen. When you run a Java application under Microsoft Windows, buttons are really Microsoft Windows buttons. When you run the same application on a Macintosh, buttons are really Macintosh buttons. When you run on a UNIX machine that uses Motif, buttons are really Motif buttons. Applications versus Applets Recall that an Applet is a Java program that runs in a web page, while an application is one that runs from the command line. An Applet is a Panel that is automatically inserted into a web page. The browser displaying the web page instantiates and adds the Applet to the proper part of the web page. The browser tells the Applet when to create its GUI (by calling the init() method of Applet) and when to start() and stop() any special processing. Applications run from a command prompt. When you execute an application from the command prompt, the interpreter starts by calling the application's main() method. Basic GUI Logic There are three steps you take to create any GUI application or applet: 1. Compose your GUI by adding components to Container objects 2. Setup event handlers to respond to user interaction with the GUI 3. Display the GUI (automatically done for applets, you must explicitly do this for applications) When you display an AWT GUI, the interpreter starts a new thread to watch for user interaction with the GUI. This new thread sits and waits until a user presses a key, clicks or moves the mouse, or any other system-level event that affects the GUI. When it receives such an event, it calls one of the event handlers you set up for the GUI. Note that the event handler code is executed within the thread that watches the GUI! (This is an import point that will be revisited later when events are reviewed.)

Because this extra thread exists, your main method can simply end after it displays the GUI. This makes GUI code very simple to write in AWT. Compose the GUI, setup event handlers, then display. A Simple Example The following simple example shows some GUI code. This example creates an Applet that contains just an Applet.

import java.awt.Button; import java.applet.Applet; public class AButton extends Applet { public void init() { // STEP 1: Compose the GUI Button beepButton = new Button("Beep"); add(beepButton); // STEP 2: Setup Event handlers beepButton.addActionListener(new Beeper()); // STEP 3: Display the GUI (automatic -- this is an applet) } } In step 2 from above, event handling is set up by adding an instance of a listener class to the button. When the button is pressed, a certain method in the listener class is called. In this example, the listener class implements ActionListener (because Button requires it). When the button is pressed, the button calls the actionPerformed() method of the listener class. Event handling is discussed in detail later in this module. Suppose you want to produce a "beep" sound when the button is pressed. You can define your event handler as follows: import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.Component; public class Beeper implements ActionListener { public void actionPerformed(ActionEvent event) { Component c = (Component)event.getSource(); c.getToolkit().beep();

} } When actionPerformed() is called, it produces a beep sound on the computer (assuming your system is sound capable). To try this applet, create a simple HTML page as follows. Then test the HTML page by running appletviewer or by loading the HTML file in a browser that supports the Java Runtime Environment (JRE). Note that in this case, the browser must support at least version 1.1 of the JRE, as the example uses the event handling capabilities introduced with that release. AWT Components All AWT components extend class Component. Think of Component as the "root of all evil" for AWT. Having this single class is rather useful, as the library designers can put a lot of common code into it. Next, examine each of the AWT components below. Most, but not all, directly extend Component. You've used most of the components should be familiar to you. Buttons A Button has a single line label and may be "pushed" with a mouse click.

import java.awt.*; import java.applet.Applet; public class ButtonTest extends Applet { public void init() { Button button = new Button("OK"); add(button); } }

Note that in the above example there is no event handling added; pressing the button will not do anything. The AWT button has no direct support for images as labels. Canvas A Canvas is a graphical component representing a region where you can draw things such as rectangles, circles, and text strings. The name comes from a painter's canvas. You subclass Canvas to override its default paint() method to define your own components.

You can subclass Canvas to provide a custom graphic in an applet. import java.awt.Canvas; import java.awt.Graphics; class DrawingRegion extends Canvas { public DrawingRegion() { setSize(100, 50); } public void paint(Graphics g) { g.drawRect(0, 0, 99, 49); // draw border g.drawString("A Canvas", 20,20); } } Then you use it like any other component, adding it to a parent container, for example in an Applet subclass. import java.applet.Applet; public class CanvasPaintTest extends Applet { public void init() { DrawingRegion region = new DrawingRegion(); add(region); }

The Canvas class is frequently extended to create new component types, for example image buttons. However, starting with the JRE 1.1, you can now directly subclass Component directly to create lightweight, transparent widgets. Checkbox A Checkbox is a label with a small pushbutton. The state of a Checkbox is either true (button is checked) or false (button not checked). The default initial state is false. Clicking a Checkbox toggles its state. For example:

import java.awt.*; import java.applet.Applet; public class CheckboxSimpleTest extends Applet { public void init() { Checkbox m = new Checkbox("Allow Mixed Case"); add(m); } } To set a Checkbox initially true use an alternate constructor:

import java.awt.*; import java.applet.Applet; public class CheckboxSimpleTest2 extends Applet { public void init() { Checkbox m = new Checkbox("Label", true); add(m); } }

CheckboxGroup A CheckboxGroup is used to control the behavior of a group of Checkbox objects (each of which has a true or false state). Exactly one of the Checkbox objects is allowed to be true at one time. Checkbox objects controlled with a CheckboxGroup are usually referred to as "radio buttons". The following example illustrates the basic idea behind radio buttons.

import java.awt.*; import java.applet.Applet; public class CheckboxGroupTest extends Applet { public void init() { // create button controller CheckboxGroup cbg = new CheckboxGroup(); Checkbox cb1 = new Checkbox("Show lowercase only", cbg, true); Checkbox cb2 = new Checkbox("Show uppercase only", cbg, false); add(cb1); add(cb2); } } Choice Choice objects are drop-down lists. The visible label of the Choice object is the currently selected entry of the Choice.

import java.awt.*; import java.applet.Applet; public class ChoiceSimpleTest extends Applet { public void init() { Choice rgb = new Choice(); rgb.add("Red"); rgb.add("Green"); rgb.add("Blue"); add(rgb); } } The first item added is the initial selection. Label A Label is a displayed Label object. It is usually used to help indicate what other parts of the GUI do, such as the purpose of a neighboring text field.

import java.awt.*; import java.applet.Applet; public class LabelTest extends Applet { public void init() { add(new Label("A label")); // right justify next label add(new Label("Another label", Label.RIGHT)); } } Like the Button component, a Label is restricted to a single line of text. List A List is a scrolling list box that allows you to select one or more items.

Multiple selections may be used by passing true as the second argument to the constructor.

import java.awt.*; import java.applet.Applet; public class ListSimpleTest extends Applet { public void init() { List list = new List(5, false); list.add("Seattle"); list.add("Washington"); list.add("New York"); list.add("Chicago"); list.add("Miami"); list.add("San Jose"); list.add("Denver"); add(list); } } The constructor may contain a preferred number of lines to display. The current LayoutManager may choose to respect or ignore this request. Scrollbar A Scrollbar is a "slider" widget with characteristics specified by integer values that are set during Scrollbar construction. Both horizontal and vertical sliders are available.

import java.awt.*; import java.applet.Applet;

// A simple example that makes a Scrollbar appear public class ScrollbarSimpleTest extends Applet { public void init() { Scrollbar sb = new Scrollbar(Scrollbar.HORIZONTAL, 0, // initial value is 0 5, // width of slider -100, 105); // range -100 to 100 add(sb); } } The maximum value of the Scrollbar is determined by subtracting the Scrollbar width from the maximum setting (last parameter). TextField A TextField is a scrollable text display object with one row of characters. The preferred width of the field may be specified during construction and an initial string may be specified.

import java.awt.*; import java.applet.Applet; public class TextFieldSimpleTest extends Applet { public void init() { TextField f1 = new TextField("type something"); add(f1); } } Tips:y y

y y

Call setEditable(true) to make the field read-only. The constructor has an optional width parameter. This does not control the number of characters in the TextField, but is merely a suggestion of the preferred width on the screen. Note that layout managers may choose to respect or ignore this preferred width. For password fields: field.setEchoChar('?');

To clear/reset: field.setEchoChar((char)0); TextArea A TextArea is a multi-row text field that displays a single string of characters, where newline ('\n' or '\n\r' or '\r', depending on platform) ends each row. The width and height of the field is set at construction, but the text can be scrolled up/down and left/right.

import java.awt.*; import java.applet.Applet; public class TextAreaSimpleTest extends Applet { TextArea disp; public void init() { disp = new TextArea("Code goes here", 10, 30); add(disp); } } There is no way, for example, to put the cursor at beginning of row five, only to put the cursor at single dimension position 50. There is a four-argument constructor that accepts a fourth parameter of a scrollbar policy. The different settings are the class constants: SCROLLBARS_BOTH, SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE, and SCROLLBARS_VERTICAL_ONLY. When the horizontal (bottom) scrollbar is not present, the text will wrap.

import java.awt.*; import java.applet.Applet; public class TextAreaScroll extends Applet { String s = "This is a very long message " + "It should wrap when there is " + "no horizontal scrollbar."; public void init() { add(new TextArea (s, 4, 15, TextArea.SCROLLBARS_NONE)); add(new TextArea (s, 4, 15, TextArea.SCROLLBARS_BOTH)); add(new TextArea (s, 4, 15, TextArea.SCROLLBARS_HORIZONTAL_ONLY)); add(new TextArea (s, 4, 15, TextArea.SCROLLBARS_VERTICAL_ONLY)); } } Common Component Methods All AWT components share the 100-plus methods inherited from the Component class. Some of the most useful and commonly-used methods are listed below:y y y y

getSize() - Gets current size of component, as a Dimension. Dimension d = someComponent.getSize(); int height = d.height; int width = d.width; Note: With the Java 2 Platform, you can directly access the width and height using the getWidth() and getHeight() methods. This is more efficient, as the component doesn't need to create a new Dimension object. For example: int height = someComponent.getHeight(); // Java 2 Platform only!

int width = someComponent.getWidth(); // Java 2 Platform only! If you're using the Java 2 platform, you should only use getSize() if you really need a Dimension object!y y y y

getLocation() - Gets position of component, relative to containing component, as a Point. Point p = someComponent.getLocation(); int x = p.x; int y = p.y; Note: With the Java 2 Platform, you can directly access the x and y parts of the location using getX() and getY(). This is more efficient, as the component doesn't have to create a new Point object. For example: int x = someComponent.getX(); // Java 2 Platform only! int y = someComponent.getY(); // Java 2 Platform only! If you're using the Java 2 platform, you should only use getLocation() if you really need a Point object!

y y y y y y y y y y

getLocationOnScreen() - Gets the position of the component relative to the upperleft corner of the computer screen, as a Point. Point p = someComponent.getLocationOnScreen(); int x = p.x; int y = p.y; getBounds() - Gets current bounding Rectangle of component. Rectangle r = someComponent.getBounds(); int height = r.height; int width = r.width; int x = r.x; int y = r.y; This is like a combination of calling getLocation() and getSize(). Note: If you're using the Java 2 Platform and don't really need a Rectangle object, you should use getX(), getY(), getWidth(), and getHeight() instead.

y

y

setEnabled(boolean) - Toggles the state of the component. If set to true, the component will react to user input and appear normal. If set to false, the component will ignore user interaction, and usually appear ghosted or grayedout. setVisible(boolean) - Toggles the visibility state of the component. If set to true, the component will appear on the screen if it is contained in a visible container. If false, the component will not appear on the screen. Note that if a component is marked as not visible, any layout manager that is responsible for that component will usually proceed with the layout algorithm as though the component were not in the parent container! This means that making a component invisible will not simply make it disappear while reserving its space in the GUI. Making the component invisible will cause the layout of its sibling components to rea djust!

y y

setBackground(Color)/setForeground(Color) Changes background/foreground colors. setFont(Font) - Changes font of text within component.

component

Containers A Container is a Component, so may be nested. Class Panel is the most commonly-used Panel and can be extended to partition GUIs. Class Applet is a specialized Panel for running programs within a browser. Common Container Methods Besides the 100-plus methods inherited from the Component class, all Container subclasses inherit the behavior of about 50 common methods of Container (most of which just override a method of Component). While the most common method of Container used add(), has already been briefly discussed, if you need to access the list of components within a container, you may find the getComponentCount(), getComponents(), and getComponent(int) methods helpful. ScrollPane The ScrollPane container was introduced with the 1.1 release of the Java Runtime Environment (JRE) to provide a new Container with automatic scrolling of any one large Component. That large object could be anything from an image that is too big for the display area to a bunch of spreadsheet cells. All the event handling mechanisms for scrolling are managed for you. Also, there is no LayoutManager for a ScrollPane since there is only a single object within it. The following example demonstrates the scrolling of a large image. Since an Image object is not a Component, the image must be drawn by a component such as a Canvas.

import java.awt.*; import java.applet.*; class ImageCanvas extends Component { private Image image; public ImageCanvas(Image i) { image = i; }

public void paint(Graphics g) { if (image != null) g.drawImage(image, 0, 0, this); } } public class ScrollingImage extends Applet { public void init() { setLayout(new BorderLayout()); ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); Image im = getImage(getCodeBase(), "./images/SMarea.gif"); sp.add(new ImageCanvas(im)); add(sp, BorderLayout.CENTER); } } Event Handling Events Beginning with the 1.1 version of the JRE, objects register as listeners for events. If there are no listeners when an event happens, nothing happens. If there are twenty listeners registered, each is given an opportunity to process the event, in an undefined order. With a Button, for example, activating the button notifies any registered ActionListener objects. Consider SimpleButtonEvent applet which creates a Button instance and registers itself as the listener for the button's action events: import java.awt.*; import java.awt.event.*; import java.applet.Applet; public class SimpleButtonEvent extends Applet implements ActionListener { private Button b; public void init() { b = new Button("Press me"); b.addActionListener(this); add(b); } public void actionPerformed(ActionEvent e) { // If the target of the event was our Button // In this example, the check is not // truly necessary as we only listen to // a single button if ( e.getSource() == b ) {

getGraphics().drawString("OUCH",20,20); } } } Notice that any class can implement ActionListener, including, in this case, the applet itself. All listeners are always notified. If you don't want an event to be processed further, you can call the AWTEvent.consume() method. However each listener would then need to check for consumption using the isConsumed() method. Consuming events primarily stops events from being processed by the system, after every listener is notified. So, if you want to reject keyboard input from the user, you can consume() the KeyEvent. All the KeyListener implementers will still be notified, but the character will not be displayed. (Consumption only works for InputEvent and its subclasses.) So, here is how everything works:y y

y y

Components generate subclasses of AWTEvent when something interesting happens. Event sources permit any class to be a listener using the addXXXListener() method, where XXX is the event type you can listen for, for example addActionListener(). You can also remove listeners using the removeXXXListener() methods. If there is an add/removeXXXListener() pair, then the component is a source for the event when the appropriate action happens. In order to be an event handler you have to implement the listener type, otherwise, you cannot be added, ActionListener being one such type. Some listener types are special and require you to implement multiple methods. For instance, if you are interested in key events, and register a KeyListener, you have to implement three methods, one for key press, one for key release, and one for both, key typed. If you only care about key typed events, it doesn't make sense to have to stub out the other two methods. There are special classes out there called adapters that implement the listener interfaces and stub out all the methods. Then, you only need t o subclass the adapter and override the necessary method(s).

AWTEvent Events subclass the AWTEvent class. And nearly every event-type has an associated Listener interface, PaintEvent and InputEvent do not. (With PaintEvent, you just override paint() and update(), for InputEvent, you listen for subclass events, since it is abstract. Low-level Events Low-level events represent a low-level input or window operation, like a key press, mouse movement, or window opening. The following table displays the different lowlevel events, and the operations that generate each event (each operation corresponds to a method of the listener interface):

ComponentEvent Hiding, moving, resizing, showing ContainerEvent FocusEvent KeyEvent MouseEvent WindowEvent Adding/removing component Getting/losing focus Pressing, releasing, or typing (both) a key Clicking, dragging, entering, exiting, moving, pressing, or releasing Iconifying, deiconifying, opening, closing, really closed, activating, deactivating

For instance, typing the letter 'A' on the keyboard generates three events, one for pressing, one for releasing, and one for typing. Depending upon your interests, you can do something for any of the three events. Semantic Events Semantic events represent interaction with a GUI component; for instance selecting a button, or changing the text of a text field. Which components generate which events is shown in the next section. ActionEven AdjustmentEvent ItemEvent TextEvent Event Sources The following table represents the different event sources. Keep in mind the object hierarchy. For instance, when Component is an event source for something, so are all its subclasses: Low-Level Events ComponentListener FocusListener KeyListener MouseListener MouseMotionListener ContainerListener WindowListener Do the command Value adjusted State changed Text changed

Component

Container Window Semantic Events Button List MenuItem TextField

ActionListener

Choice Checkbox CheckboxMenuItem List Scrollbar TextArea TextField

ItemListener AdjustmentListener TextListener

Notice that although there is only one MouseEvent class, the listeners are spread across two interfaces. This is for performance issues. Since motion mouse events are generated more frequently, if you have no interest in them, you can ignore them more easily, without the performance hit. Event Listeners Each listener interface is paired with one event type and contains a method for each type of event the event class embodies. For instance, the KeyListener contains three methods, one for each type of event that the KeyEvent has: keyPressed(), keyReleased(), and keyTyped(). Listener interfaces and their methods Interface ActionListener AdjustmentListener Method(s) actionPerformed(ActionEvent e) adjustmentValueChanged(AdjustmentEvent e) componentHidden(ComponentEvent e) ComponentListener componentMoved(ComponentEvent e) componentResized(ComponentEvent e) componentShown(ComponentEvent e) ContainerListener FocusListener ItemListener KeyListener componentAdded(ContainerEvent e) componentRemoved(ContainerEvent e) focusGained(FocusEvent e) focusLost(FocusEvent e) itemStateChanged(ItemEvent e) keyPressed(KeyEvent e) keyReleased(KeyEvent e) keyTyped(KeyEvent e) mouseClicked(MouseEvent e) MouseListener mouseEntered(MouseEvent e) mouseExited(MouseEvent e) mousePressed(MouseEvent e)

mouseReleased(MouseEvent e) MouseMotionListener TextListener mouseDragged(MouseEvent e) mouseMoved(MouseEvent e) textValueChanged(TextEvent e) windowActivated(WindowEvent e) windowClosed(WindowEvent e) windowClosing(WindowEvent e) WindowListener windowDeactivated(WindowEvent e) windowDeiconified(WindowEvent e) windowIconified(WindowEvent e) windowOpened(WindowEvent e) Event Adapters Since the low-level event listeners have multiple methods to implement, there are event adapter classes to ease the pain. Instead of implementing the interface and stubbing out the methods you do not care about, you can subclass the appropriate ad apter class and just override the one or two methods you are interested in. Since the semantic listeners only contain one method to implement, there is no need for adapter classes. public class MyKeyAdapter extends KeyAdapter { public void keyTyped(KeyEvent e) { System.out.println("User typed: " + KeyEvent.getKeyText(e.getKeyCode())); } } Button Pressing Example The following code demonstrates the basic concept a little more beyond the earlier example. There are three buttons within a Frame, their displayed labels may be internationalized so you need to preserve their purpose within a command associated with the button. Based upon which button is pressed, a different action occurs.

import java.awt.*; import java.awt.event.*; public class Activator { public static void main(String[] args) { Button b;

ActionListener al = new MyActionListener(); Frame f = new Frame("Hello Java"); f.add(b = new Button("Hola"), BorderLayout.NORTH); b.setActionCommand("Hello"); b.addActionListener(al); f.add(b = new Button("Aloha"), BorderLayout.CENTER); b.addActionListener(al); f.add(b = new Button("Adios"), BorderLayout.SOUTH); b.setActionCommand("Quit"); b.addActionListener(al); f.pack(); f.show(); } } class MyActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Action Command is not necessarily label String s = e.getActionCommand(); if (s.equals("Quit")) { System.exit(0); } else if (s.equals("Hello")) { System.out.println("Bon Jour"); } else { System.out.println(s + " selected"); } } } Since this is an application, you need to save the source (as Activator.java), compile it, and run it outside the browser. Also, if you wanted to avoid checking which button was selected, you can associate a different ActionListener to each button, instead of one to all. This is actually how many Integrated Development Environments (IDEs) generate their code. Adapters Example The following code demonstrates using an adapter as an anonymous inner class to draw a rectangle within an applet. The mouse press signifies the top left corner to draw, with the mouse release the bottom right. import java.awt.*; import java.awt.event.*; public class Draw extends java.applet.Applet { public void init() { addMouseListener(

new MouseAdapter() { int savedX, savedY; public void mousePressed(MouseEvent e) { savedX = e.getX(); savedY = e.getY(); } public void mouseReleased(MouseEvent e) { Graphics g = Draw.this.getGraphics(); g.drawRect(savedX, savedY, e.getX()-savedX, e.getY()-savedY); } } ); } } Applications and Menus GUI-based Applications To create a window for your application, define a subclass of Frame (a Window with a title, menubar, and border) and have the main method construct an instance of that class. Applications respond to events in the same way as applets do. The following example, BasicApplication, responds to the native window toolkit quit, or closing, operation:

import java.awt.*; import java.awt.event.*; public class BasicApplication extends Frame { public BasicApplication() { super("BasicApplication Title"); setSize(200, 200); // add a demo component to this frame add(new Label("Application Template...", Label.CENTER),

BorderLayout.CENTER); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { setVisible(false); dispose(); System.exit(0); } }); } public static void main(String[] args) { BasicApplication app = new BasicApplication(); app.setVisible(true); } } Consider an application that displays the x,y location of the last mouse click and provides a button to reset the displayed x,y coordinates to 0,0:

import java.awt.*; import java.awt.event.*; public class CursorFrame extends Frame { TextField a, b; Button btn; public CursorFrame() { super("CursorFrame"); setSize(400, 200); setLayout(new FlowLayout()); add(new Label("Click the mouse...")); a = new TextField("0", 4); b = new TextField("0", 4); btn = new Button("RESET"); add(a); add(b); add(btn); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { a.setText(String.valueOf(e.getX())); b.setText(String.valueOf(e.getY())); } }); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {

setVisible(false); dispose(); System.exit(0); } }); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { a.setText("0"); b.setText("0"); } }); } public static void main(String[] args) { CursorFrame app = new CursorFrame(); app.setVisible(true); } } This application provides anonymous classes to handle mouse events, application window closing events, and the action event for resetting the text fields that report mouse coordinates. When you have a very common operation, such as handling application window closing events, it often makes sense to abstract out this behavior and handle it elsewhere. In this case, it's logical to do this by extending the existing Frame class, creating the specialization AppFrame: import java.awt.*; import java.awt.event.*; public class AppFrame extends Frame implements WindowListener { public AppFrame(String title) { super(title); addWindowListener(this); } public void windowClosing(WindowEvent e) { setVisible(false); dispose(); System.exit(0); } public void windowClosed(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowOpened(WindowEvent e) {} }

AppFrame directly implements WindowListener, providing empty methods for all but one window event, namely, the window closing operation. With this definition, applications such as CursorFrame can extend AppFrame instead of Frame and avoid having to provide the anonymous class for window closing operations: Exercises 1. Displaying Files 2. Converting an Applet to an Application Applications: Dialog Boxes A Dialog is a window that requires input from the user. Components may be added to the Dialog like any other container. Like a Frame, a Dialog is initially invisible. You must call the method setVisible() to activate the dialog box.

import java.awt.*; import java.awt.event.*; public class DialogFrame extends AppFrame { Dialog d; public DialogFrame() { super("DialogFrame"); setSize(200, 100); Button btn, dbtn; add(btn = new Button("Press for Dialog Box"), BorderLayout.SOUTH); d = new Dialog(this, "Dialog Box", false); d.setSize(150, 150); d.add(new Label("This is the dialog box."), BorderLayout.CENTER); d.add(dbtn = new Button("OK"), BorderLayout.SOUTH); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { d.setVisible(true); } }); dbtn.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { d.setVisible(false); } }); d.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { d.setVisible(false); } }); } public static void main(String[] args) { DialogFrame app = new DialogFrame(); app.setVisible(true); } } Again, you can define anonymous classes on the fly for: 1. Activating the dialog window from the main application's command button. 2. Deactivating the dialog window from the dialog's command button. 3. Deactivating the dialog window in response to a native window system's closing operation. Although the anonymous class functionality is quite elegant, it is inconvenient to have to repeatedly include the window-closing functionality for every dialog instance that your applications instantiate by coding and registering the anonymous window adapter class. As with AppFrame, you can define a specialization of Dialog that adds this functionality and thereafter simply use the enhanced class. For example, WMDialog provides this functionality: import java.awt.*; import java.awt.event.*; public class WMDialog extends Dialog implements WindowListener { public WMDialog(Frame ref, String title, boolean modal) { super(ref, title, modal); addWindowListener(this); } public void windowClosing(WindowEvent e) { setVisible(false); } public void windowClosed(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowOpened(WindowEvent e) {} }

Exercise 3. OK Dialog Applications: File Dialog Boxes The utility class FileDialog is useful for getting file names from the application user. FileDialog.getFile() reports the name of the file selected by the user. If this returns null, the user decided to cancel the selection. Currently, usage of FileDialog is limited to applications and trusted applets. Exercise 4. Display a File from FileDialog Applications: Menus An application can have a MenuBar object containing Menu objects that are comprised of MenuItem objects. Each MenuItem can be a string, menu, checkbox, or separator (a line across the menu). To add menus to any Frame or subclass of Frame Create a MenuBar MenuBar mb = new MenuBar(); Create a Menu Menu m = new Menu("File"); Create your MenuItem choices and add each to the Menu, in the order you want them to appear, from top to bottom. 6. m.add(new MenuItem("Open")); 7. m.addSeparator(); // add a separator 8. m.add(new CheckboxMenuItem("Allow writing")); 9. // Create submenu 10. Menu sub = new Menu("Options..."); 11. sub.add(new MenuItem("Option 1")); 12. m.add(sub); // add sub to File menu 13. Add each Menu to the MenuBar in the order you want them to appear, from left to right. 14. mb.add(m); // add File menu to bar 15. Add the MenuBar to the Frame by calling the setMenuBar() method . 16. setMenuBar(mb); // set menu bar of your Frame 1. 2. 3. 4. 5. The following program, MainWindow, creates an application window with a menu bar and several menus using the strategy outlined above:

import java.awt.*; import java.awt.event.*; // Make a main window with two top-level menus: File and Help. // Help has a submenu and demonstrates a few interesting menu items. public class MainWindow extends Frame { public MainWindow() { super("Menu System Test Window"); setSize(200, 200); // make a top level File menu FileMenu fileMenu = new FileMenu(this); // make a top level Help menu HelpMenu helpMenu = new HelpMenu(this); // make a menu bar for this frame // and add top level menus File and Menu MenuBar mb = new MenuBar(); mb.add(fileMenu); mb.add(helpMenu); setMenuBar(mb); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { exit(); } }); } public void exit() { setVisible(false); // hide the Frame dispose(); // tell windowing system to free resources System.exit(0); // exit } public static void main(String args[]) {

MainWindow w = new MainWindow(); w.setVisible(true); } } // Encapsulate the look and behavior of the File menu class FileMenu extends Menu implements ActionListener { MainWindow mw; // who owns us? public FileMenu(MainWindow m) { super("File"); mw = m; MenuItem mi; add(mi = new MenuItem("Open")); mi.addActionListener(this); add(mi = new MenuItem("Close")); mi.addActionListener(this); add(mi = new MenuItem("Exit")); mi.addActionListener(this); } // respond to the Exit menu choice public void actionPerformed(ActionEvent e) { String item = e.getActionCommand(); if (item.equals("Exit")) mw.exit(); else System.out.println("Selected FileMenu " + item); } } // Encapsulate the look and behavior of the Help menu class HelpMenu extends Menu implements ActionListener { MainWindow mw; // who owns us? public HelpMenu(MainWindow m) { super("Help"); mw = m; MenuItem mi; add(mi = new MenuItem("Fundamentals")); mi.addActionListener(this); add(mi = new MenuItem("Advanced")); mi.addActionListener(this); addSeparator(); add(mi = new CheckboxMenuItem("Have Read The Manual")); mi.addActionListener(this); add(mi = new CheckboxMenuItem("Have Not Read The Manual")); mi.addActionListener(this); // make a Misc sub menu of Help menu Menu subMenu = new Menu("Misc"); subMenu.add(mi = new MenuItem("Help!!!"));

mi.addActionListener(this); subMenu.add(mi = new MenuItem("Why did that happen?")); mi.addActionListener(this); add(subMenu); } // respond to a few menu items public void actionPerformed(ActionEvent e) { String item = e.getActionCommand(); if (item.equals("Fundamentals")) System.out.println("Fundamentals"); else if (item.equals("Help!!!")) System.out.println("Help!!!"); // etc... } } Exercise 5. Menus Menu Shortcuts One nice feature of the MenuItem class is its ability to provide menu shortcuts or speed keys. For instance, in most applications that provide printing capabilities, pressing CtrlP initiates the printing process. When you create a MenuItem you can specify the shortcut associated with it. If the user happens to press the speed key, the action event is triggered for the menu item. If you want to create two menu items with speed keys, Ctrl-P for Print and Shift-Ctrl-P for Print Preview, the following code would do that: file.add (mi = new MenuItem ("Print", new MenuShortcut('p'))); file.add (mi = new MenuItem ("Print Preview", new MenuShortcut('p', true))); The example above uses Ctrl-P and Shift-Ctrl-P shortcuts on Windows/Motif. The use of Ctrl for the shortcut key is defined by the Toolkit method getMenuShortcutKeyMask(). For the Macintosh, this would be the Command key. An optional boolean parameter to the constructor determines the need for the Shift key appropriate to the platform. Pop-up Menus One restriction of the Menu class is that it can only be added to a Frame. If you want a menu in an Applet, you are out of luck (unless you use the Swing component set). While not necessarily a perfect solution, you can associate a pop-up menu with any Component, of which Applet is a subclass. A PopupMenu is similar to a Menu in that it holds MenuItem objects. However, instead of appearing at the top of a Frame, you pop

the popup menu up over any component, usually when the user generates the appropriate mouse event. The actual mouse interaction to generate the event is platform specific so there is the means to determine if a MouseEvent triggers the pop-up menu via the MouseEvent.isPopupTrigger() method. It is then your responsibility to position and display the PopupMenu. The following program, PopupApplication, demonstrates this portable triggering of a pop-up menu, as well as activating a pop-up menu from a command button:

import java.awt.*; import java.awt.event.*; public class PopupApplication extends AppFrame { Button btn; TextField msg; PopupAppMenu m; public PopupApplication() { super("PopupApplication"); setSize(200, 200); btn = new Button("Press for pop-up menu..."); add(btn, BorderLayout.NORTH); msg = new TextField(); msg.setEditable(false); add(msg, BorderLayout.SOUTH); m = new PopupAppMenu(this); add(m); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m.show(btn, 10, 10); } }); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) m.show(e.getComponent(), e.getX(), e.getY()); } public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger())

m.show(e.getComponent(), e.getX(), e.getY()); } }); } public static void main(String[] args) { PopupApplication app = new PopupApplication(); app.setVisible(true); } } class PopupAppMenu extends PopupMenu implements ActionListener { PopupApplication ref; public PopupAppMenu(PopupApplication ref) { super("File"); this.ref = ref; MenuItem mi; add(mi = new MenuItem("Copy")); mi.addActionListener(this); add(mi = new MenuItem("Cut")); mi.addActionListener(this); add(mi = new MenuItem("Paste")); mi.addActionListener(this); } public void actionPerformed(ActionEvent e) { String item = e.getActionCommand(); ref.msg.setText("Selected menu item: " + item); } }

Chapter -4Swing Programming

Introduction Swing is a large set of components ranging from the very simple, such as labels, to the very complex, such as tables, trees, and styled text documents. Almost all Swing components are derived from a single parent called JComponent which extends the AWT Container class. Thus, Swing is best described as a layer on top of AWT rather than a replacement for it. Z-order Swing components are referred to as lightweights while AWT components are referred to as heavyweights. The difference between lightweight and heavyweight components is z-order: the notion of depth or layering. Each heavyweight component occupies its own z-order layer. All lightweight components are contained inside heavyweight components and maintain their own layering scheme defined by Swing. When we place a heavyweight inside another heavyweight container it will, by definition, overlap all lightweights in that container. What this ultimately means is that we should avoid using bo th heavyweight and lightweight components in the same container whenever possible. This does not mean that we can never mix AWT and Swing components successfully. It just means we have to be careful and know which situations are safe and which are not. Since we probably won t be able to completely eliminate the use of heavyweight components anytime soon, we have to find ways to make the two technologies work together in an acceptable way. The most important rule to follow is that we should never place heavyweight components inside lightweight containers that commonly support overlapping children. Some examples of these containers are JInternalFrame, JScrollPane, JLayeredPane, and JDesktopPane. Secondly, if we use a popup menu in a container holding a heavy weight component, we need to force that popup to be heavyweight. To control this for a specific JPopupMenu instance we can use its setLightWeightPopupEnabled() method. Note: For JMenus (which use JPopupMenus to display their contents) we first have to use the getPopupMenu() method to retrieve the associated popup menu. Once retrieved we can then call setLightWeightPopupEnabled(false) on that popup to enforce heavyweight functionality. This needs to be done with each JMenu in our application, including menus contained within menus, etc. Alternatively we can call JPopupMenu s static setDefaultLightWeightPopupEnabled() method, and pass it a value of false to force all popups in a Java session to be heavyweight. Note that this will only affect popup menus created after this call is made. It is therefore a good idea to call this method early within initialization. Platform independence The most remarkable thing about Swing components is that they are written in 100% Java and do not depend on peer components, as most AWT components do. This means that a Swing button or text area will look and function identically on Macintosh, Solaris, Linux, and Windows platforms. This design eliminates the need to test and debug applications on each target platform.

Note: The only exceptions to this are four heavyweight Swing components that are direct subclasses of AWT classes relying on platform-dependent peers: JApplet, JDialog, JFrame, and JWindow. See chapter 3. Swing package overview javax.swing : Contains the most basic Swing components, default component models, and interfaces. (Most of the classes shown in Figure 1.2 are contained in this package.) javax.swing.border : Classes and interfaces used to define specific border styles. Note that borders can be shared by any number of Swing components, as they are not components themselves. javax.swing.colorchooser : Classes and interfaces supporting the JColorChooser component, used for color selection. (This package also contains some int eresting undocumented private classes.) javax.swing.event : The event package contains all Swing-specific event types and listeners. Swing components also support events and listeners defined in java.awt.event and java.beans. javax.swing.filechooser : Classes and interfaces supporting the JFileChooser component, used for file selection. javax.swing.plaf : Contains the pluggable look-and-feel API used to define custom user interface components. Most of the classes in this package are abstract. They are subclassed and implemented by look-and-feel implementations such as metal, motif, and basic. The classes in this package are intended for use only by developers who, for one reason or another, cannot build on top of existing look -and-feels. javax.swing.plaf.basic : Consists of the Basic look-and-feel implementation which all look-and-feels provided with Swing are built on top of. We are normally expected to subclass the classes in this package if we want to create our own customized look-andfeel. javax.swing.plaf.metal : Metal is the default look-and-feel of Swing components. It is the only look-and-feel that ships with Swing not designed to be consistent with a specific platform. javax.swing.plaf.multi : This is the Multiplexing look-and-feel. This is not a regular lookand-feel implementation in that it does not define the actual look or feel of any components. Rather, it provides the ability to combine several look -and-feels for simultanteous use. A typical example might be using an audio-based look-and-feel in combination with metal or motif. Currently Java 2 does not ship with any multiplexing look-and-feel implemenations (however, rumor has it that the Swing team is working on an audio look-and-feel as we write this). javax.swing.table : Classes and interfaces supporting the JTable control. This component

is us t ust i ti x swi r i tr

t u r t with ut r uiri

i

s r

sh t h

r

It su ts

rts

hi h

r

t xt ss s i t r s us st u ts th i ws ust i ti it r ti s

th t xt ts i u i su th s u ts hi h i hti r ust i ti

rt r t

x swi t xt ht his xt si ts H L su rt w s t xt whi w w r writi this i it x swi x swi x swi hi h t xt ht t xt rt rs r u rt rt r

th t xt t i s su rt r H L i t r writt x u us this ur r it is r r t

rsi

H u rti t

L ts th J r hi r r i h ri ti t t It su ts his rts

t i s su

rR F

tr t is us r ust u u ti

ss s i t r s su r th is i ti with ut r uiri h u it t i s su

u

x swi /r

rt

i

MVC

MVC is a w known object oriented user inter ace desi n decomposition that dates back to the late 1970s Components are broken down into three parts a model, a view, and a controller Each Swing component is based on a more modern version of this design. Before we discuss how MVC works in Swing, we need to understand how it was originally designed to work. Note: The three-way separation described here is only used today by a small number of user interface frameworks, VisualWorks being the most notable.

c

ec u e

Model The model is responsible for maintaining all aspects of the component state. This includes, for example, such values as the pressed/unpressed state of a push button, a text component s character data and information about how it is structured, etc. A model may be responsible for indirect communication with the with the view and the controller. By indirect we mean that the model does not