Sie sind auf Seite 1von 15

Visual Programming Unit V

UNIT V

Visual J++: Introduction to VJ++ - Applet Wizard – Handling events – Multithreading –


Animation Techniques – Animating images – Applets and networking.

1. INTRODUCTION TO VJ++

1.1 JAVA APPLET WIZARD

The VJ++ Java Applet Wizard walks you through a set of option pages to create the
classes and code for a Java applet and provides a sample HTML file for browsing the
applet. The framework for the Wizard-created applet supports multithreading, image
animation, mouse event handling, and parameters read from the HTML. After the Wizard
is finished and you compile the applet, you can test it with Internet Explorer (IE) 3.0 or
later, with other browsers that support Java, or with VJ++'s standalone interpreter,
jview.exe. In the current version of VJ++, IE is the only browser you can use for
debugging. (Before you can install VJ++ from http://www.microsoft.com/visualj, you
must install IE 3.0 from http://www.microsoft.com/ie.)

When you first run VJ++, you will see menu bars typical of those in VC++ and a project
workspace window with InfoView (a powerful integrated Help system). To begin the
Java Applet Wizard, select the File menu and click New. Double-click the Project
Workspace option to display the New Project Workspace dialog box, as shown in Screen
1.

SCREEN 1: SCREEN 2:

Displaying the Java Applet Wizard's Selecting how you want to run
New Project Workspace dialog box your program

In the Type list, select Java Applet Wizard. Enter a name for your project in the Name
text box (I used boingi, short for "boing image") and click Create. The Java Applet
Wizard - Step 1 of 5 dialog box appears, as in Screen 2.
Visual Programming Unit V

Select As an applet only for how you want to run your program. (If you plan to use
jview.exe to test your applet, you must choose As an applet and as an application.) Click
Next, and the Java Applet Wizard - Step 2 of 5 dialog box appears, as in Screen 3.

SCREEN 3: SCREEN 4:

Creating the HTML debugging file Specifying multithreading and


and changing the size of your applet animation support

Selecting Yes, please to Would you like a sample HTML file? creates the HTML file for
debugging. The initial size fields (Width, Height) let you change the size of the applet.
Click Next, and the Java Applet Wizard - Step 3 of 5 dialog box appears. Our example
includes animation, so keep the default option, Yes, please, for both multithreading and
animation support, as shown in Screen 4. Click Next, and the Java Applet Wizard - Step
4 of 5 dialog box appears, as in Screen 5. Enter the applet parameters from Table 1 on
this screen.

SCREEN 6:
SCREEN 5:

Entering the applet parameters Viewing the information the


applet returns to the browser
Visual Programming Unit V

TABLE 1: Boingi Applet Parameters


Def-
Name Member Type Description
Value
minSpeed m_minSpeed int 2 min speed in either x or y
maxSpeed m_maxSpeed int 10 max speed in either x or y

Click Next, and the Java Applet Wizard - Step 5 of 5 dialog box appears, as in Screen 6.
This dialog box shows the information the applet will return to the browser. Click Finish,
and the New Project Information dialog box displays a summary of specifications for the
project. Click OK to complete the Wizard and return to the main VJ++ window.

From the Build menu, select Build boingi to build the project. To run it, select Debug
from the Build menu and Go from the Debug submenu (or simply press F5). If you are
asked to specify the path to a browser, I recommend you use IE 3.0 or later, but the applet
will run properly with Netscape and other browsers that support Java. The applet the
Wizard will create animates a series of .gif files as a spinning globe.

Applet with Attitude

The spinning globe example the Wizard creates is OK, but let's extend the example by
bouncing the globe around, changing its direction and speed whenever it hits the applet's
boundary. Let's jump right into the code by opening the boingi.java file (part of which is
in Listing 1) that the Wizard generated. At callout A in Listing 1, add the instance data
shown in Listing 2. The program uses this instance data to keep track of the previous
position and to calculate the next position of the image as it moves across the applet.

Next, at the end of the public void init() method (in Listing 3), comment out (// signals a
comment line) the call to resize() and save the range of the applet in m_rng, as follows:

//resize(320,240); // save the applet's range


m_rng = size();

Now move down two more methods in the boingi.java file to the private void
displayImage(Graphics g) method. Modify the code to appear as in Listing 4, and you're
ready to compile and test the new Java code.

The displayImage() method in Listing 4 first clears the previous image. Then the method
displays a new image at the current position (m_nImgX, m_nImgY). Finally, the method
calls the travelImage() method to calculate a new position to display the next image. The
Wizard-generated code (commented out in Listing 4) displays the image in the center of
the applet; the new code moves the image on each call to the displayImage() method.

The travelImage() method saves the previous image coordinates and calls the
checkForTurnaround() method to calculate a new vector (m_incX, m_incY) when the
Visual Programming Unit V

image is about to hit the applet's boundary. The checkForTurnaround() method checks
whether the image is out-of-bounds; if so, it calculates a new speed in the opposite
direction.

2. HANDLING EVENTS

Java events are part of the Java AWT package. An event is the way that the AWT
communicates to you, as the programmer, and to other Java AWT components that
something has happened. That something can be input from the user (mouse movements
or clicks, keypresses), changes in the system environment (a window opening or closing,
the window being scrolled up or down), or a host of other things that might, in some way,
be interesting to the operation of the program.

In other words, whenever just about anything happens to a Java AWT component,
including an applet, an event is generated. Some events are handled by the AWT or by
the browser without your needing to do anything. paint() methods, for example, are
generated and handled by the browser—all you have to do is tell the AWT what you want
painted when it gets to your part of the window. Some events, however (for example, a
mouse click inside the boundaries of your applet), you might need to know about.
Writing your Java programs to handle these kinds of events enables you to get input from
the user and have your applet change its behavior based on that input.

Mouse Clicks

Now start with the most common event you might be interested in: mouse clicks. Mouse-
click events occur when the user clicks the mouse somewhere in the body of your applet.
You can intercept mouse clicks to do very simple things—for example, to toggle the
sound on and off in your applet, to move to the next slide in a presentation, or to clear the
screen and start over—or you can use mouse clicks in conjunction with mouse
movements to perform more complex motions inside your applet.

mouseDown and mouseUp

When you click the mouse once, the AWT generates two events: a mouseDown event
when the mouse button is pressed, and a mouseUp event when the button is released.
Why two individual events for a single mouse action? Because you might want to do
different things for the "down" and the "up." For example, look at a pull-down menu. The
mouseDown extends the menu, and the mouseUp selects an item (with mouseDrags
between—but you'll learn about that one later today). If you have only one event for both
actions (mouseUp and mouseDown), you cannot implement that sort of user interaction.

Handling mouse events in your applet is easy—all you have to do is override the proper
method definition in your applet. That method will be called when that particular event
occurs. Here's an example of the method signature for a mouseDown event:
Visual Programming Unit V

public boolean mouseDown(Event evt, int x, int y)

{
...
}

The mouseDown() method (and the mouseUp() method as well) takes three parameters:
the event itself and the x and y coordinates where the mouseDown or mouseUp event
occurred.

The event argument is an instance of the class Event. All system events generate an
instance of the Event class, which contains information about where and when the event
took place, the kind of event it is, and other information that you might want to know
about this event. Sometimes having a handle to that event object is useful, as you'll
discover later in this section.

The x and the y coordinates of the event, as passed in through the x and y arguments, are
particularly nice to know because you can use them to determine precisely where the
mouse click took place.

For example, here's a simple method that grabs the current x and y positions when a
mouseDown event occurs:

public boolean mouseDown(Event evt, int x, int y)


{

m_iMousex = x;
m_iMousey = y;
return true;
}

By including this method in an applet, every time the user clicks the mouse inside your
applet, the data members m_iMousex and m_iMousey will be updated.

Note that this method, unlike the other system methods you've studied thus far, returns a
Boolean value instead of not returning anything (void). This will become important later
today when you create user interfaces and then manage input to these interfaces; having
an event handler return true or false determines whether a given UI component can
intercept an event or whether it needs to pass it on to the enclosing component. The
general rule is that if your method deals with the event, it should return true.
Visual Programming Unit V

Mouse Movements

Every time the mouse is moved a single pixel in any direction, a mouse move event is
generated. There are two mouse movement events: mouse drags, where the movement
occurs with the mouse button pressed down, and plain mouse movements, where the
mouse button isn't pressed.

To manage mouse movement events, use the mouseDrag() and mouseMove() methods.

mouseDrag and mouseMove

The mouseDrag() and mouseMove() methods, when included in your applet code,
intercept and handle mouse movement events. The mouseMove() method, for plain
mouse pointer movements without the mouse button pressed, looks much like the mouse-
click methods:

public boolean mouseMove(Event evt, int x, int y)


{
...
}

The mouseDrag() method handles mouse movements made with the mouse button
pressed down (a complete dragging movement consists of a mouseDown event, a series
of mouseDrag events for each pixel the mouse is moved, and a mouseUp event when the
button is released). The mouseDrag() method looks like this:

Keyboard events are generated whenever users press a key on the keyboard. By using key
events, you can get hold of the values of the keys that were pressed to perform an action
or merely to get character input from the users of your applet.

The keyDown and keyUp Methods

To capture a keyboard event, use the keyDown() method:

public boolean keyDown(Event evt, int key)


{
...
}

The keys generated by keyDown events (and passed into keyDown() as the key
argument) are integers representing ASCII character values, which include alphanumeric
characters, function keys, tabs, returns, and so on. To use them as characters (for
example, to print them), you need to cast them to characters:
currentchar = (char)key;

Here's a simple example of a keyDown() method that does nothing but set the data
member m_cLastKey to the character value of the key you just typed.
Visual Programming Unit V

public boolean keyDown(Event evt, int key)

{
m_cLastKey = (char)key;
return true;

As with mouse clicks, each keyDown event also has a corresponding keyUp event. To
intercept keyUp events, use the keyUp() method:

public booklean keyUp(Event evt, int key)

{
...

Table 13.1. Standard keys defined by the event class.

Class Variable Represented Key

Event.HOME The Home key

Event.END The End key

Event.PGUP The Page Up key

Event.PGDN The Page Down key

Event.UP The up arrow

Event.DOWN The down arrow

Event.LEFT The left arrow

Event.RIGHT The right arrow


Visual Programming Unit V

3. MULTITHREADING

The Java language contains one feature that is so dangerous, so difficult to avoid using,
so hard to use correctly, and so pervasively used incorrectly that it has to rank as a serious
design flaw. That feature is multithreading. Experienced programmers are aware of the
hazards associated with multithreading, and employ various strategies to ameliorate the
problem.

3.1 THE EXTENT OF MULTITHREADING IN VISUAL J++

Languages and environments other than Java permit the use of multiple threads. But Java
applications are virtually impossible to write without using them, and most apps use a lot
of them. Even the most trivial applet will have three threads: the applet's main run loop,
the Java virtual machine's event loop, and the Java display manager's paint loop.

To this we can probably add even more threads for applications with animation timing
loops, sound, and network communication. There can be no argument that Java's runtime
environment is replete with threads, all running simultaneously and manipulating the
same data. To deal with this chaos, Java provides just one low-level construct: the
synchronized keyword.

3.2 THE HAZARDS OF SYNCHRONIZATION

Synchronization is both necessary and sufficient to control the execution of multithreaded


code, but that's akin to saying a raft and an oar are enough to cross any body of water.
Sure, you can do it. In practice, however, synchronization is very difficult to use
correctly. Here's a list of some of the problems inherent with synchronization:

• If you don't use synchronization enough, and in the right places, your program
will execute using inconsistent sets of data, and thus will produce unpredictable
results. This situation is called a data race, because multiple threads race each
other to produce and/or consume their common data. This kind of problem
typically manifests itself in your programs as random, nonreproducible bugs
which, if you investigate the situation, appear to result from "impossible"
configurations of your data, such as

if(a==1)

b=2;

if((a==1)&&(b!=2)) { throw new Error("impossible error!"); }


Visual Programming Unit V

• If you use synchronization too much, or in the wrong places, your threads can
deadlock, with two or more processes permanently blocked because they are
waiting for each other to relinquish some resource they both want to use. This
kind of problem typically results in the application "locking up."
• Threads that temporarily have nothing to do must be suspended and resumed
when there is something for them to do again. If a thread should be resumed, but
no other thread issues the command, a permanently stalled thread can result.

3.3 COMMON STRATEGIES FOR DEALING WITH MULTIPLE THREADS

There are some good rules of thumb that are commonly used in Java programming.

• Do all of your drawing in one place: either do all your drawing in the paint
method, or do all your drawing in your run loop, and use the paint method only to
set a "needs to be painted" flag. Conversely, do not do any drawing directly in
response to various mouse, button, and network events.
• Use semaphores to indicate when data is ready to be consumed by another thread.
• Do as little as possible within synchronized methods. In particular, do not do
anything that will not finish after some clearly foreseeable series of actions. Do
not do anything inside synchronization that might block indefinitely, particularly
I/O.
• Use local variables rather than global variables.
• Try to organize your code so each piece of data is manipulated in exactly one
thread. Any data that is not shared between threads is guaranteed to be safe.
• Synchronize code that you know will be used by multiple processes and that uses
state that may be shared among the processes.

4. ANIMATION TECHNIQUES
Many Java applets perform animation, whether it's the classic, cartoon-style animation of
Duke waving, program-generated lines such as flowing sine waves, or simply moving
static images across the screen. No comprehensive, direct-manipulation tools exist (yet)
for creating Java animations.

4.1 BASIC ANIMATION TECHNIQUES

Many forms of animation are possible in Java. What all of them have in common is that
they create some kind of motion on the screen by drawing successive frames at a
relatively high speed (usually about 10-20 times per second).

We will start by creating a simple template applet for doing animations and slowly
elaborate it until we arrive at a fairly complete applet.
Visual Programming Unit V

4.2 USING A THREAD

To update the screen multiple times per second, you need to create a new Java thread that
contains an animation loop. The animation loop is responsible for keeping track of the
current frame and for requesting periodic screen updates. To implement a thread, you
must either create a subclass of thread or adhere to the runnable interface.

A common mistake is to put the animation loop in the paint( ) method of an applet. Doing
so will have strange side effects because it holds up the main AWT thread, which is in
charge of all drawing and event handling.

4.3 KEEPING A CONSTANT FRAME RATE

In the example above, the applet simply sleeps for a fixed amount of time between
frames. This has the drawback that you sometimes wait too long. To get 10 frames per
second you should not wait 100 milliseconds between frames, because you lose some
time just running the thread.

4.3.1 OVERRIDING THE UPDATE( ) METHOD

When the AWT receives a repaint request for an applet, it calls the applet's update( )
method. By default, the update( ) method clears the applet's background and then calls
the paint() method. By overriding the update( ) method to include the drawing code that
used to be in the paint( ) method, we avoid having the applet's entire area cleared with
every repaint. Now that the background is no longer cleared automatically, we need to do
it ourselves in the update( ) method.

4.3.2 DOUBLE BUFFERING

Another way of reducing the flashing between frames is to use double buffering. This
technique is used in many animation applets. The general principle is that you create an
offscreen image, you draw a frame into the image, and then you slap the entire image
onto the screen with one call to drawImage(). The advantage is that most of the drawing
is done offscreen. The final painting of the offscreen image onto the screen is usually
much more efficient than painting the frame directly to the screen.

The sine wave applet with double buffering is shown in Example6Applet. You will see
that the animation is pretty smooth and you don't need any special tricks when drawing
the frame. The only disadvantage is that you have to allocate an offscreen image that is as
large as the drawing area. If the drawing area is very large, this may demand quite a lot of
memory.

The Java applet is a different sort of beast from the typical application that executes on
your PC or workstation. For one thing, it doesn't sit quietly on the hard drive waiting for
your attention; a Java applet sits on the other side of a network connection waiting for
you (and many others) to pull it across the network. Once the applet has made the
Visual Programming Unit V

journey, it comes to life and begins to download the resources it needs. Unfortunately, all
of this network activity results in one thing: delay. In contrast to an application on your
hard drive, an applet must expect, and deal constructively with network delay.

For this reason, the Java class library was designed to support asynchronous loading of
media, such as images. Asynchronous loading means that loading occurs out of step with
the rest of the application -- in another thread -- in the background. In fact, what might be
thought of as one operation, the loading of an image from across the network, actually
occurs in two distinct stages, which often occur asynchronously. These stages are: image
definition and the actual downloading of the image.

In this column, I will take a close look at the mechanics of image loading from the
perspective of a Java applet or similar network-based Java application. I will also provide
a step-by-step demonstration of how to load and draw images within an applet.

5. ANIMATING IMAGES

5.1 GETTING THE PICTURE WITH THE IMAGE CLASS

An instance of the Image class represents image data. The image data does not need to
reside locally; it may exist on another computer. In fact, it may not exist at all. An
instance of the Image class is more like a reference to image data, than a container for
image data.

Consider an image on a computer across a network. The creation of an instance of the


Image class on a local computer does not cause the image data to be pulled across the
network. This is true because instantiation of the Image class does not cause
reconstruction of the image data. The Image class doesn't even provide methods for
initiating image reconstruction. (This class does, however, provide access to an
ImageProducer object that does provide such methods -- I will talk about image
producers next month.)

Although the Image class doesn't store image data, it does provide methods for obtaining
information about an image. The following methods return such information:

intget Height (ImageObserverobs);

intget Width (ImageObserverobs);

Object getProperty (String nm, ImageObserver obs);

The height and width values returned from the first two methods indicate the size of the
image, in pixels. Properties, on the other hand, are image-format-specific pieces of
information about an image, and are retrieved by name. The only property mentioned
specifically in the Image class API is the comment property. It should contain a
Visual Programming Unit V

description of the image, or something similar. These methods return invalid values (the
getHeight( ) and getWidth( ) methods both return -1 and the getProperty( ) method
returns null) if the desired information is currently unavailable.

All three methods require an instance of a class that implements the ImageObserver
interface as a parameter. An image observer is an object that expects to be notified when
information about an image becomes available (I will talk about image observers next
month). The Applet class implements this interface and we'll be using it as the image
observer throughout this column.

Image objects are not created by instantiating the Image class directly. Instead, other
classes in the Abstract Windowing Toolkit (AWT) provide methods for creating images.
For example, the Applet class provides methods for creating instances of the Image class
from a URL:

Image getImage(URL url);

Image getImage(URL url, String nm);

You can also create an instance of the Image class with methods provided by the
Component class:

Image createImage(ImageProducer prod);

Image createImage(int w, int h);

5.2 DRAWING IMAGES WITH THE GRAPHICS CLASS

As you might expect, the Graphics class plays a pivotal role in the use of images. It
would be impossible for me to include a thorough discussion of the Graphics class and its
role in the space I have available

Along with methods for drawing text and simple geometric shapes, the Graphics class
provides methods for drawing images. In fact, it provides four related methods:

boolean drawImage(Image i, int x, int y, ImageObserver obs);

boolean drawImage(Image i, int x, int y, Color c, ImageObserver obs);

boolean drawImage(Image i, int x, int y, int w, int h, Color c, ImageObserver obs);

boolean drawImage(Image i, int x, int y, int w, int h, ImageObserver obs);

These methods have several parameters in common. Each method requires an instance of
the Image class and the x and y coordinates at which to draw the image. Each method
also requires an instance of a class that implements the ImageObserver interface.
Visual Programming Unit V

6. APPLETS AND NETWORKING

At the example applet's core is public-key cryptography, introduced earlier in this series.
Code signed using the private key of the signer can be run on client machines once the
public key corresponding to the signer is deemed as trusted on the respective machine.
We'll also discuss how policy files, which accord permissions and keystore, can be used
as a repository for public and private keys. Moreover, we'll highlight the Java 2 SDK
security tools and Netscape's sign tool, since they enable deployment.

This series does not intend to provide a comprehensive guide to computer security.
Computer security is a multifaceted issue touching several disciplines, departments, and
cultures. Investments in technologies should be followed up with investments in
personnel training, strict enforcement of policies, and periodic review of the overall
security policy.

6.1 APPLICATION SECURITY

Let's begin our investigation by looking at application security First, a quick note about
writeFile.java, the code used in this article to illustrate the security features in Java 2.
This program is a slightly modified version of the applet code provided by Sun, available
over the Web to illustrate some of the features of Java 2 security. The program, modified
to provide application support, attempts to create and write a file on the local file system.
Access to a local filesystem is screened by the security manager. We will see throughout
this article how this particular operation can be permitted in a secure manner.

Running the byte code generated in a Java 2 Runtime Environment, Standard Edition
(JRE) will let the application modify the file on the local file system by default, since the
default policy does not subject Java 2 applications to a security manager. This policy is
justified because applications are typically locally generated code and not downloaded
over the network.

The cases illustrated above represent extreme examples of security policy. In the former
case, the application was not subject to any control; in the latter, it was subject to a very
rigid control. In most cases it will be necessary to set the policy somewhere in between.

You can accomplish an in-between policy using a policy file. To do so, create a policy
file called all policy in the working directory:

Running the same piece of code with the following command line will allow
modification of the local filesystem:

$ java -Djava.security.manager -Djava.security.policy=all.policy writeFile


Visual Programming Unit V

6.1.1 NETWORKING APPLETS

In this example, the application was subject to the security manager, but the overall
policy was governed by the policy file, which allowed all files on the local filesystem to
be modified. A stricter policy might have been to allow modification of only the relevant
file..

Let us take a look at applet security and contrast it with application security.

Any user sitting behind a corporate firewall or proxy server and use Netscape Navigator
as their primary Web browser. These users cannot make use of Java applets that connect
back to the applet's originating server because of Java applet security restrictions. For
example, the applet-based site java.sun.com:81 and various applets that reside on the
www.gamelan.com site, or are linked to from it, are not accessible to users behind a
firewall. The typical error that comes up is: "# Security Exception:
socket.connect:www.machine_name.com->www.machine_name.com."

To get around this security restriction, all you need to do is edit your local Domain Name
Service (DNS) resolver configuration. For most Unix and Windows systems, this is often
done by editing your local HOSTS file:

• Under Unix-like systems, this HOSTS file is "/etc/hosts"


• Under Windows 3.x and 95 systems, this file is "c:\windows\hosts"
• Under Windows NT systems, this file is

"c:\Winnt_version\system32\drivers\etc\hosts," where Winnt_version is specific

to the NT version.

Simply map the "machine_name" where the applet came from to some arbitrary Internet
address. That is, add a line like the following to your HOSTS file:
"www.machine_name.com 1.2.3.4." Then restart your Navigator browser, and you'll find
that now you can use applets from www.machine_name.com.

6.1.2 A REAL EXAMPLE

As stated above, with Navigator, when a firewall/proxy server is present and the internal
network does not provide external DNS resolution users cannot access the Java applet-
based site at java.sun.com:81. The typical circumstance involves a user not having the
capability to do external DNS resolution. Most (if not all) companies do NOT provide
external DNS resolution. Simply by adding the line "1.2.3.4 java.sun.com" to their
HOSTS file, users can now fully access java.sun.com: 81.
Visual Programming Unit V

6.1.3 HOW IT ALL WORKS

I believe the reason adding a line to the HOSTS file gives users access to the site is
because of a small security glitch in how the applet security manager checks to see what
IP address the applet came from. In the example above, the site of origin is java.sun.com,
which maps to an IP address of 1.2.3.4 on my machine. Then when the applet wants to
connect back to java.sun.com for whatever reason, the applet security manager again
checks to see what IP address the applet wants to connect back to. Once again,
java.sun.com will map to 1.2.3.4. The applet security manager then compares the
identical 1.2.3.4 responses and allows the connection to be made.

The security glitch occurs at the point that this second applet request is made: What is
supposed to happen based on any secondary applet request is that the URL request should
be rewritten from http://java.sun.com/whatever to http://1.2.3.4/whatever before the
request gets passed from the applet to the browser and then to the firewall/proxy server.
But the URL request does not get rewritten. The applet requests keeps the URL request as
http://java.sun.com, which forces the proxy to do another DNS resolution.