WebDeveloper.com ®: Where Web Developers and Designers Learn How to Build Web Sites, Program in Java and JavaScript, and More!   
Web Developer Resource DirectoryWebDev Jobs  
Animated GIFs
CSS
CSS Properties
Database
Design
Flash
HTML
HTML 4.01 Tags
JavaScript
.NET
PHP
Reference
Security
Site Management
Video
XML/RSS
WD Forums
 Client-Side
  Development

    CSS
    Graphics
    HTML
    JavaScript
    XML
    Dreamweaver/FrontPage
    Multimedia
    Web Video
    General
    Accessibility

 Server-Side
  Development

    ASP
    Perl
    PHP
    .NET
    Java
    SQL
    Other

 Web Development
  Business Issues

    Business Matters
    Website Reviews

 E-Commerce
    Domain Names
    Search Engines

 Etc.
    Computer Issues
    Forum Software
    Feedback
    The Coffee Lounge



Script Downloads
Form Focus

Featured: August 20, 2008
Description: This snippet places the cursor in a selected form field upon page load. It uses the ID attribute, making it easy to target any field, regardless of form changes. Easy to add to any form. Updated.

Get Script

Hosting Search
Unix   Windows
PHP   Webmail

Sign up for the free WebDeveloper E-mail newsletter!


JupiterWeb Commerce
Partners & Affiliates
Partner With Us
Web Design
Calling Cards
Phone Cards
KVM over IP
Memory
Online Education
Computer Deals
Promotional Golf
Promotional Pens
PDA Phones & Cases
Desktop Computers
Promote Your Website
KVM Switches
Logo Design

internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

Download these IBM Software Construction tools today!

eKit: Simplify the Creation of SIP Applications
Discover how you can deliver Session Initiation Protocol (SIP) based applications with speed and quality. With the attached collection of articles, podcasts, webcasts, youll learn how to use IBM Rational software to model, code and test SIP-based applications.

Webcast: Hacking 101--Top 10 Attacks in Web Apps
Learn about the three most common web application attacks, including how they occur and what can be done to prevent them.

Whitepaper: Best Practices for Software Analysis
With more complex software comes a greater likelihood of users running into an application defect. Detecting and correcting these defects as early as possible will lead to better application quality and a better user experience. This whitepaper introduces IBM Rational Software Analyzer and discusses its use in detecting and correcting application defects.

Webcast: Smart Agile Development Within Dispersed Teams
A repository that promotes asset collaboration and governance while ensuring quality can be a key cornerstone of a successful agile development strategy. Hear how IBM Rational Asset Manager can help empower distributed agile teams.

The Java Programming Tutorial: Vol. 2
Classes, Threads, and Applets

by Mark C. Reynolds
Reprinted from Web Developer® magazine, Vol. 2 No. 2 May/June 1996 © 1996

The Java language provides everything one would expect in a modern object-oriented programming language. It has all the standard control constructs, a reasonably comprehensible object model, and tools for creating standalone applications or smaller applets that are designed to run inside Web pages.

The power of Java does not reside primarily in the language itself, however; it resides in the libraries that accompany it: the Java Class Hierarchy. The first part of this tutorial, in the Spring 1996 issue of Web Developer®, dealt with the Java language and the construction of simple applets. This part will focus on the set of Java classes associated with graphics, known as the Advanced Windowing Toolkit, or AWT. Applet construction will also be revisited, with an eye toward event handling and multitasking.

Programming low-level graphics is often like constructing a sand castle one grain of sand at a time. Higher-level toolkits allow more rapid construction of user interfaces, but they lack fine control and involve certain design compromises and limitations. Very high-level GUI builders can be extremely powerful, but they can also be the source of enormous frustration when asked to do something outside their repertoire. Where does Java's AWT fit in?

In many ways, the Advanced Windowing Toolkit will seem very familiar to anyone who has ever used a toolkit to write a graphics program under almost any windowing system. The design issues are the same: the suite of components (buttons, labels, scrollbars, cuboctohedra) that are available, how these components are arranged visually, and the mechanisms involved in communicating between the components and the application program itself. You want a button labeled Cancel, you want it in the lower right-hand corner of your graphic, and you want to tie it to a function named CancelAction(), for example. The AWT gives you several ways to accomplish these goals. It also provides a set of very powerful classes and methods that give Java programmers some distinctly different higher-level tools (as well as some distinctly different programming challenges).

There are four aspects to programming with the AWT: establishing the layout, implementing the components, manipulating global resources such as colors and fonts, and handling events. Each of these aspects interacts with the others in well-defined ways.

One of the strengths of the AWT is that it was designed to be platform-independent. This does not guarantee that any piece of AWT code will look exactly the same on a Unix machine, a Windows 95 box, or a Macintosh, but only that the behavior of the AWT will be the same on each. We will consider each of the four aspects of AWT programming in turn.

Unlike many toolkits, the AWT does not really enforce a specific layout policy. Instead, it provides five standard layout classes that correspond to commonly encountered types of layouts. These are the BorderLayout, CardLayout, FlowLayout, GridLayout, and GridBagLayout classes. It is also possible to create one's own layout class (although this is not for the faint of heart) or to eschew any formalized layout altogether and place one's components at absolute (x,y) coordinates. Most AWT applets will end up using FlowLayout, GridLayout, or BorderLayout, which are conceptually the simplest.

In order to understand the idea behind the layout classes, we will start with a simple example using BorderLayout. In a BorderLayout, components may be placed at the North, South, East, or West locations, or they may be placed in the Center. It is called a "border" layout because each component that's added sticks to its corresponding border (with the exception of the Center component, which occupies the unused space in the middle). Figure 1 shows a code fragment that creates a border layout with four buttons, one at each cardinal point.

This code first creates a new instance of the BorderLayout class using the new operator, and then calls the setLayout method with that instance as its sole argument. What is the purpose of this statement? We can guess that this establishes the BorderLayout as the default layout for the applet. The real reason that it works is that a Java applet is actually an instance of the Applet class, and the Applet class is actually a subclass of a graphical container class known as a Panel. Just as any applet must extend the Applet class, so Applet extends Panel. The call to setLayout is actually manipulating the panel in which the applet resides.

The next four statements create four buttons named for their intended locations. The text of each button is taken from the instance variables NORTH, SOUTH, EAST, and WEST, which have been declared with the keywords static and final.

This is the standard approach to declaring constants in Java. Java has no const keyword, like C++. Instead it uses the keywords final, which indicates that the instance variable may not be changed, and static, which says that this instance variable is shared among all instances of its class. It is very important to realize that while the static keyword has the same meaning of permanence it has in C and C++, it does not affect the scope of the instance variable, as it would in C and C++. Other keywords (private and protected) are used for that purpose.

After the buttons have been created, they are entered into the layout using the add method. A final call is then made to the show method to ensure that all the components are drawn. Each of the five layout classes has its own peculiar form of the add method. In the case of BorderLayout, it wants add to have two arguments: The first is the placement location, and the second is the component to be added. Note that in this example, the button labels are identical to their placement locations. This is by no means necessary; the buttons could just as easily have been named Moe, Larry, Curly, and Shemp. The add method, however, must be given one of the cardinal directions exactly as shown or it will fail to understand. You cannot add(Norte, el_amador), even if el_amador is a valid button instance.

This example is, of course, extremely boring. The buttons are not connected to anything, so that pressing them will not have any meaningful results. It is straightforward to modify this code into a complete Applet that will do something meaningful. In particular, we can change it so that it will illustrate something interesting about applet events. A text-area component will be added at the Center location. We will also add an event handler, which will write information into that text area about the events received by the applet. The complete code for this simple Evlab (Event Lab) applet is shown in Figure 2.

This code uses a little bit of everything. It declares and uses the BorderLayout class; it incorporates three types of graphical components (Button, TextField and TextArea); it makes use of one of the global graphical elements, namely Font; and it incorporates some rudimentary event handling. It also represents a new type of applet, one that is not threaded. This last point will be discussed in more detail below.

The init() method of the Evlab applet is similar to the BLex.java code shown previously. This code make more extensive use of other graphical components. It still places buttons at the North, East, and West locations. This version of init() creates a TextField and puts that at South, and also creates a TextArea and puts that in the Center position of the BorderLayout. These two text components are almost identical to the HTML elements of the same names. A TextField is used to display a single line of text. It may be read/write or read-only. In our example it has been created with no initial text (the first argument to the constructor is "") and has width 70. By default, TextFields are read/write so that it will be possible to type into this particular component.

The construction of the centrally placed TextArea is a little more elaborate. A TextArea is a multiline text entity, which can also be read/write or read-only. In our case it has been created with an initial size of 10 x 70. The call to the setEditable() method with the false argument declares that the user will not be able to modify the contexts of this text area. A specific font to be used is also set by calling the setFont() method. This is done for both the editable text field down South and the text area in the Center.

The font was obtained by calling the Font() constructor with three arguments: the name of the font, the font style, and the font size. Times Roman is one of a small number of fonts that Java guarantees to provide (the others include Helvetica and Courier). The style argument indicates whether we want the plain version (Font.PLAIN), bold version (Font.BOLD), italic version (Font.ITALIC), or some other style. Styles may be combined, so that if the second argument had been Font.BOLD + Font.ITALIC, Java would have tried to find a Times Roman 14-point font that was both bold and italic. The init() method concludes by successively adding each of the five components to the BorderLayout and then calling show() to insure that they are shown.

In addition to the init() method, which initializes the graphic environment, this applet also has an action() method (and two placeholder methods, start() and stop(), discussed below).

As one might guess, the action method is used to capture events. The action() method is passed two arguments: an Event instance ev and an Object arg. The Event instance ev describes the event that just happened. The second argument, arg, represents component-specific information that the AWT gives you to help handle the event. When a button is pressed, for example, the action method will be called, with arg set equal to the label of the button that was just pressed.


Figure 3

In our Evlab example, we do not attempt to do anything to the incoming events and their arguments except to display information about them. The first statement of the action() method uses the setText method of the text area tfe to display the event id of the incoming event. Using setText ensures that any previous text in this text area is cleared. The event id is a somewhat mystical number describing the type of event. The next four statements of the action() method append additional information about the event ev and the argument arg to the text area. Since each string used ends with a newline "\n", each will be on its own line. The x and y coordinates of the site of the event are printed, as well as the target of the event (which component was affected), and the arg field of the Event ev. It is often the case that ev.arg and the argument arg are identical. Figure 3 shows the appearance of the Evlab applet after the West button has been pressed.

The final statement of the action() method is return(false). This is necessary because our action() method overrides a built-in Applet method that returns a Boolean value. The return code is used to indicate if the event has been handled. Like many windowing systems, the AWT uses a hierarchical event-handling model. Just as graphics may be built in a layered fashion, so events may be generated and handled at any of the various levels. Our action() method returns false to indicate that the event has not been handled.

An excellent way to use the event lab applet to demonstrate the event hierarchy is to type some text into the text field in the South position, and then hit Return. This will generate an event that will be displayed in the text area in the center of the applet. The third line of text, the one describing the event target, will be too long, and it will be necessary to scroll the text area using the horizontal scrollbar on the bottom of the text area. When you hit this scrollbar, it will scroll the central text area, and it will not generate another event. In reality, when the scrollbar is activated it does generate another event, but that event is intercepted and processed by the text area itself. The result is the scroll action that we see.

Since that event is completely processed by the text area, it never reaches the action() event handler of the Evlab applet--it has been consumed by the text area's own built-in event handler. The reader is strongly encouraged to experiment with the Evlab applet by placing other types of graphical components (as described below) in the South position and determining what types of events are generated.

What of the other layout methods? FlowLayout is the simplest of the five types. When this form of layout is used, components are added from left to right. When all the available space in a given row has been used, a new row will be created. Rows can be CENTER justified (the default) or LEFT or RIGHT justified. FlowLayout is typically used for rows of similar items, such as buttons. An example of this layout approach will be given below.

GridLayout is a structured layout format in which graphical components are placed on a grid with a fixed size. If a GridLayout is created with a grid of 3 rows by 5 columns, for example, then we can add a component at location (2,3), which will correspond to the third column of the second row. GridBagLayout is an extensible form of grid layout, in which the grid is permitted to expand as new elements are added. GridBagLayout is the most general layout strategy, and also the most complex. Finally, CardLayout implements a HyperCard-style layout. Graphical components are added to individual cards, which are then displayed sequentially, rather than simultaneously.

Figure 4 lists the graphical components, such as Button, and the global graphical elements, such as Font, that are provided by the AWT. If you have ever done any sort of graphics programming, many of these items will be very familiar to you. A List is actually a scrolling listbox, rather than a Lisp-like List. A CheckboxGroup is called a radio button by most other graphics systems.

Note that the list of graphical components includes items that are containers, such as Panel. This makes the hierarchical organization described above possible. We could modify the event lab applet to put a Panel in the central position, give that panel its own layout, and then proceed to add components to that panel. This panel might have a GridLayout, even though the applet's panel has a BorderLayout.

The Java API provides all the details on using the various components and global elements. Rather than attempt an exhaustive description of all of them, this article will conclude by focusing on a small set of classes related to animation. We have already seen a very simple demonstration of image loading in the first part of this tutorial. A Java VCR will now be developed that will allow us to load a set of images and then smoothly display them under user control. To do this, however, we must make a short detour and discuss the topic of threads in Java.

Threads

Most modern operating systems support the concept of multitasking, in which multiple independent processes timeshare the same physical CPU. Soon after the first multitasking OS was created, it was realized that it would be delightful to support the same sort of multiple-task model inside application programs, rather than just at the command-line level. The first implementations of this idea were cumbersome, and involved copying the entire code and data space of the parent task to all newly created child tasks. Eventually, the concept of threads was born. A thread is a lightweight task, without much context. Good thread implementations should allow a top-level application to create multiple threads, assign each a piece of work, coordinate them, and ultimately clean up when all of them are done. Java supports just such a threaded programming model.

The concept of threads not only applies to stand-alone Java applications, but also to Java applets. The Evlab.java applet in Figure 2 does not make explicit use of threads. It has an init() method, which is called when the applet is loaded; a start() method, which is called after loading is complete (and when a previously loaded Java page is revisited); and a stop() method, which is called when a page containing the Java applet is unloaded, or when another page is visited. Both the tiny applets shown in the first part of the tutorial, as well as the Vcr.java applet shown in Figure 5, are threaded applets. We know this because they implement the Runnable interface: The phrase "implements Runnable" is part of the applet's class declaration. A runnable applet will also have a run() method, which will be entered whenever a new thread is created for the applet's class. If this explanation seems a bit obscure, it should become more clear as we work through the code of the Java VCR.

The init() method does a number of very familiar things. Its goal is to load a number of images, specified by the HTML PARAM attribute "nimgs." These images are to be found at a location specified by the PARAM "imgloc" relative to the document base. Each image has a numerical suffix, as well as the suffix .gif. Thus if nimgs is 10 and imgloc is images/myanim, then the applet will look for its images in files named images/myanim1.gif through images/myanim10.gif. The first few lines of the init() method retrieve these parameters from the HTML environment using getParameter() and do some sanity checking. If everything seems reasonable, a new instance of the MediaTracker class is created and stored in the instance variable tracker. Space is also allocated for an array of nimgs images in the instance variable imgs. A for loop is then used to attempt to load each of the images into that array. Note that two loop variables are used, because the imgs[] array is 0-indexed, while the image names have suffixes starting from 1.

The for loop also contains the statement tracker.addImage(imgs[i], 0). The MediaTracker class is being used to keep track of the progress of the images being loaded. This is necessary because getImage() does not actually get the image--it simply arranges to start getting it. The call to the addImage() method of tracker tells the tracker instance to begin keeping track of that image. The second argument to addImage() is an arbitrary ID, 0 in this case, which can be used to subsequently inquire about the progress of all images with that ID. Effectively, we are placing all the images in a single pool, associated with ID 0, whose status will be queried later.

The init() method next builds a layout in which the images and a series of control buttons will be displayed. A BorderLayout with two elements is used for the applet's panel. The North element will be a Panel that will hold the images as they are being animated, while the South element will be another Panel that will hold the control buttons. The variable nodim is used to store the applet's preferred size (set by the WIDTH and HEIGHT attributes in the APPLET tag). We make the North panel as wide as the entire applet, but carve 50 pixels out of its height for the South Panel to occupy.

The South Panel is constructed using a left-justified FlowLayout. This means that the buttons we add to it will be added from left to right. The remainder of the init() method constructs these buttons, sets the button font to 14 point Helvetica, and then adds those buttons to the South panel. Note that it is necessary to explicitly say so.add(). If we had used add(), the buttons would have been added to the top-level BorderLayout. This code illustrates hierarchical organization using the AWT. The top-level applet Panel is a BorderLayout Panel with two elements: both Panels themselves. The North Panel contains no subelements, while the South Panel contains four: the four buttons labeled FWD, REV, STOP, and EJECT.

Before we discuss the run() method, let us first consider the start() and stop() methods. When init() method completes, the start() method will be invoked. It will examine the instance variable animthread, discover that it is null, and therefore will create a new Thread with the argument this. This statement actually creates a new Java Thread based on the Vcr class. The next statement, animthread.start(), runs that thread. By virtue of this statement, the run() method will be entered in that separate thread of control. The stop() method is the inverse of the start() method. When the page is unloaded, the stop() method will be called. It will terminate the animthread thread using animthread.stop(), and then reset the animthread variable to null. This ensures that if the page is reloaded or revisited, the start() method will create a new thread yet again.

The run() method and the action() event handler work together to display the images according to the controls that the user has pressed. The run() method starts out by doing some additional sanity checking. It then calls tracker.waitForID(0). This call will wait until all the images associated with ID 0 (which will be all the images in this case) have been fully loaded and prepared for on-screen display. This method invocation in encased in a peculiar construction known as a try block. Try blocks are necessary because some methods can raise exceptions, which must be caught. If such an exception occurs (because there is not enough memory for all the images, for example), the run() method returns via the catch clause.

The next two statements are a little bit of thread magic. The run method discovers the current thread and places that in the local variable me. It then lowers its own thread priority to one below the normal thread priority. This ensures that the other thread--the one actually doing the drawing--has higher priority, which is what most animation applications would want. After this is done, the run() method enters a loop. If the instance variable imginc is nonzero, then the index of the image to be displayed will be updated and a call to repaint() made to ensure that the new image is shown. The instance variable whichimg is used to hold the index of the image currently being drawn. Great care is taken to ensure that whichimg stays within range. It must never be less than 0 (the minimum image number) or greater than nimgs-1 (the maximum image number). After the image has been updated, the thread puts itself to sleep for 100 microseconds. This is another thread trick, ensuring that the Java runtime will actually look for another thread to run. After all, there really is only a single CPU and a single applet, so Java must somehow decide when to run the various threads. When Java notices that one thread has put itself to sleep, all other threads become runnable.

The action() method controls the critical-instance variables imginc and done. The action() method looks for events that are associated with Buttons. The ev.target field will always indicate the type of graphical object that was associated with the Event. Java has a very convenient operator, instanceof, to test if something opaque like ev.target is actually an instance of a particular class--Button, in this case. If the test passes, then the local variable thelab is set to the label of the Button. A four-way test is now done. If the user pressed FWD, then imginc is set to 1 and the images move forward. If REV was pressed, imginc becomes -1 and the images move backward. If STOP is pressed, imginc is set to 0, and the images move no more; they rest at the current image. Finally, if EJECT is pressed, the instance variable done is set to true.

The paint() method does the work of actually drawing the images. If done is false, then it performs a number of sanity checks, and finally uses the drawImage() method to draw the current image, represented by the index whichimg. Because of the use of the MediaTracker at the top of the run method, we can be sure that all images are loaded and ready to be drawn so that the animation will go quite smoothly. If done is true, then the paint() method clears the entire drawing area, erasing all images but leaving the buttons intact. Note that the paint() method can be called by the browser environment itself, not just by repaint(). If you obscure the applet's drawing area with another window and then reexpose it, the paint() method will be called. This is why it is important that the instance variable whichimg always have a sane value.


Figure 7

Figure 6 shows a simple HTML file that can be used to load images into the Vcr applet. Figure 7 shows the applet captured in motion, at about image 7. Sun's Tumbling Duke GIFs were used to create this particular animation, although any set of images could have been used. If you download the Java Development Kit (JDK), these images will be found in the demo/TumblingDuke/images directory.

This Vcr applet can serve as a template for animation applets, since it contains all the basic elements of a threaded graphics applet. The start() and stop() methods can be used as shown. The MediaTracker code and the Thread manipulation portions of the init() and run() methods are also quite generic. More work needs to be done in order to make this applet robust, however. The applet never checks to see if the image dimensions will actually fit in the applet's panel, for example.

Developing Yourself

The Java Development Kit may be obtained at ftp.javasoft. Almost all major platforms, including several flavors of Unix, Windows NT, Windows 95, and the Macintosh now support some version of the JDK. Sun also has a Web server at javasoft.com, but it is often overloaded. One of the most comprehensive and accessible Java sites, the Gamelan repository, has many useful public-domain classes, applets, and applications. Sun itself is publishing a set of definitive reference works on Java. The reader may also benefit from Lemay and Perkins' book Teach Yourself Java in 21 Days.




Acceptable Use Policy

JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Web Hosting | Newsletters | Tech Jobs | Shopping | E-mail Offers