分享
 
 
 

The Java Programming Tutorial: Vol. 2

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

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-orie

nted programming language. It has all the standard control constrUCts, a reaso

nably comprehensible object model, and tools for creating standalone applicati

ons or smaller applets that are designed to run inside Web pages.

The power of Java does not reside primarily in the language itself, however; i

t resides in the libraries that accompany it: the Java Class Hierarchy. The fi

rst part of this tutorial, in the Spring 1996 issue of Web Developer?, dea

lt with the Java language and the construction of simple applets. This part wi

ll focus on the set of Java classes associated with graphics, known as the Adv

anced Windowing Toolkit, or AWT. Applet construction will also be revisited, w

ith an eye toward event handling and multitaSKINg.

Programming low-level graphics is often like constructing a sand castle one gr

ain of sand at a time. Higher-level toolkits allow more rapid construction of

user interfaces, but they lack fine control and involve certain design comprom

ises 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 somet

hing 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 wind

owing system. The design issues are the same: the suite of components (buttons

, labels, scrollbars, cuboctohedra) that are available, how these components a

re arranged visually, and the mechanisms involved in communicating between the

components and the application program itself. You want a button labeled Canc

el, you want it in the lower right-hand corner of your graphic, and you want t

o tie it to a function named CancelAction(), for example. The AWT gives you se

veral ways to accomplish these goals. It also provides a set of very powerful

classes and methods that give Java programmers some distinctly different highe

r-level tools (as well as some distinctly different programming challenges).

There are four ASPects to programming with the AWT: establishing the layout, i

mplementing the components, manipulating global resources such as colors and f

onts, 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-indepen

dent. 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 b

ehavior 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 commonl

y encountered types of layouts. These are the BorderLayout, CardLayout, FlowLa

yout, 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 Bo

rderLayout, 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 plac

ed 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 sti

cks to its corresponding border (with the exception of the Center component, w

hich 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 establ

ishes the BorderLayout as the default layout for the applet. The real reason t

hat 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 k

nown as a Panel. Just as any applet must extend the Applet class, so Applet ex

tends 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 location

s. 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 cons

t 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 ins

tance variable is shared among all instances of its class. It is very importan

t 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 th

at purpose.

After the buttons have been created, they are entered into the layout using th

e 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 compone

nt 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 ju

st as easily have been named Moe, Larry, Curly, and Shemp. The add method, how

ever, 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 s

traightforward to modify this code into a complete Applet that will do somethi

ng meaningful. In particular, we can change it so that it will illustrate some

thing 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 infor

mation into that text area about the events received by the applet. The comple

te 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 BorderLayo

ut class; it incorporates three types of graphical components (Button, TextFie

ld 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 discu

ssed in more detail below.

The init() method of the Evlab applet is similar to the BLex.java code shown p

reviously. 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 comp

onents are almost identical to the Html elements of the same names. A TextFiel

d 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 t

o the constructor is "") and has width 70. By default, TextFields are read/wri

te 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-on

ly. 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 wil

l 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 ed

itable 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 H

elvetica 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 ha

d 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 succ

essively adding each of the five components to the BorderLayout and then calli

ng show() to insure that they are shown.

In addition to the init() method, which initializes the graphic environment, t

his applet also has an action() method (and two placeholder methods, start() a

nd 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 Ev

ent instance ev describes the event that just happened. The second argument, a

rg, represents component-specific information that the AWT gives you to help h

andle 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 presse

d.

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 statem

ent of the action() method uses the setText method of the text area tfe to dis

play the event id of the incoming event. Using setText ensures that any previo

us text in this text area is cleared. The event id is a somewhat mystical numb

er describing the type of event. The next four statements of the action() meth

od append additional information about the event ev and the argument arg to th

e text area. Since each string used ends with a newline "

", 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 f

ield of the Event ev. It is often the case that ev.arg and the argument arg ar

e 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 hand

led. Like many windowing systems, the AWT uses a hierarchical event-handling m

odel. Just as graphics may be built in a layered fashion, so events may be gen

erated and handled at any of the various levels. Our action() method returns f

alse to indicate that the event has not been handled.

An Excellent way to use the event lab applet to demonstrate the event hierarch

y 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 i

n the center of the applet. The third line of text, the one describing the eve

nt 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 th

is scrollbar, it will scroll the central text area, and it will not generate a

nother event. In reality, when the scrollbar is activated it does generate ano

ther event, but that event is intercepted and processed by the text area itsel

f. The result is the scroll action that we see.

Since that event is completely processed by the text area, it never reaches th

e 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 exper

iment with the Evlab applet by placing other types of graphical components (as

described below) in the South position and determining what types of events a

re 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. W

hen all the available space in a given row has been used, a new row will be cr

eated. 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 ex

ample of this layout approach will be given below.

GridLayout is a structured layout format in which graphical components are pla

ced on a grid with a fixed size. If a GridLayout is created with a grid of 3 r

ows 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, an

d also the most complex. Finally, CardLayout implements a HyperCard-style layo

ut. Graphical components are added to individual cards, which are then display

ed sequentially, rather than simultaneously.

Figure 4 lists the graphical components, such as Button, and the global graphi

cal elements, such as Font, that are provided by the AWT. If you have ever don

e 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 possi

ble. We could modify the event lab applet to put a Panel in the central positi

on, 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 glob

al elements. Rather than attempt an exhaustive description of all of them, thi

s article will conclude by focusing on a small set of classes related to anima

tion. 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 thr

eads in Java.

Threads

Most modern operating systems support the concept of multitasking, in which mu

ltiple independent processes timeshare the same physical CPU. Soon after the f

irst multitasking OS was created, it was realized that it would be delightful

to support the same sort of multiple-task model inside application programs, r

ather than just at the command-line level. The first implementations of this i

dea were cumbersome, and involved copying the entire code and data space of th

e parent task to all newly created child tasks. Eventually, the concept of thr

eads was born. A thread is a lightweight task, without much context. Good thre

ad implementations should allow a top-level application to create multiple thr

eads, assign each a piece of work, coordinate them, and ultimately clean up wh

en 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 l

oaded; 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 call

ed 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 we

ll as the Vcr.java applet shown in Figure 5, are threaded applets. We know thi

s because they implement the Runnable interface: The phrase "implements Runnab

le" is part of the applet s class declaration. A runnable applet will also hav

e a run() method, which will be entered whenever a new thread is created for t

he applet s class. If this explanation seems a bit obscure, it should become m

ore 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 fo

r its images in files named images/myanim1.gif through images/myanim10.gif. Th

e first few lines of the init() method retrieve these parameters from the HTML

environment using getParameter() and do some sanity checking. If everything s

eems reasonable, a new instance of the MediaTracker class is created and store

d in the instance variable tracker. Space is also allocated for an array of ni

mgs images in the instance variable imgs. A for loop is then used to attempt t

o load each of the images into that array. Note that two loop variables are us

ed, 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 Med

iaTracker class is being used to keep track of the progress of the images bein

g 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. E

ffectively, 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 con

trol buttons will be displayed. A BorderLayout with two elements is used for t

he 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 tha

t will hold the control buttons. The variable nodim is used to store the apple

t 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 t

hat the buttons we add to it will be added from left to right. The remainder o

f 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 ne

cessary to explicitly say so.add(). If we had used add(), the buttons would ha

ve been added to the top-level BorderLayout. This code illustrates hierarchica

l organization using the AWT. The top-level applet Panel is a BorderLayout Pan

el with two elements: both Panels themselves. The North Panel contains no sube

lements, while the South Panel contains four: the four buttons labeled FWD, RE

V, 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, an

d therefore will create a new Thread with the argument this. This statement ac

tually creates a new Java Thread based on the Vcr class. The next statement, a

nimthread.start(), runs that thread. By virtue of this statement, the run() me

thod 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() metho

d will be called. It will terminate the animthread thread using animthread.sto

p(), 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 i

mages according to the controls that the user has pressed. The run() method st

arts out by doing some additional sanity checking. It then calls tracker.waitF

orID(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 o

n-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 return

s via the catch clause.

The next two statements are a little bit of thread magic. The run method disco

vers the current thread and places that in the local variable me. It then lowe

rs its own thread priority to one below the normal thread priority. This ensur

es that the other thread--the one actually doing the drawing--has higher prior

ity, 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, t

hen the index of the image to be displayed will be updated and a call to repai

nt() made to ensure that the new image is shown. The instance variable whichim

g 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 mi

croseconds. 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 tosleep, 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 associ

ated 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 cla

ss--Button, in this case. If the test passes, then the local variable thelab i

s set to the label of the Button. A four-way test is now done. If the user pre

ssed FWD, then imginc is set to 1 and the images move forward. If REV was pres

sed, imginc becomes -1 and the images move backward. If STOP is pressed, imgin

c is set to 0, and the images move no more; they rest at the current image. Fi

nally, 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 fa

lse, then it performs a number of sanity checks, and finally uses the drawImag

e() method to draw the current image, represented by the index whichimg. Becau

se 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 g

o quite smoothly. If done is true, then the paint() method clears the entire d

rawing 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 re

paint(). 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 t

hat 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 an

y 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 contai

ns 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 manipulat

ion 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 nev

er checks to see if the image dimensions will actually fit in the applet s pan

el, for example.

Developing Yourself

The Java Development Kit may be obtained at FTP.javasoft. Almost all major pla

tforms, including several flavors of Unix, Windows NT, Windows 95, and the Mac

intosh now support some version of the JDK. Sun also has a Web server at

http://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.

Figure 1

Creating four buttons using the Border Layout Class

public static final String NORTH = "North";

public static final String SOUTH = "South";

public static final String EAST = "East";

public static final String WEST = "West";

public void init() {

setLayout(new BorderLayout());

Button no = new Button(NORTH);

Button ea = new Button(EAST);

Button we = new Button(WEST);

Button so = new Button(SOUTH);

add(NORTH, no);

add(SOUTH, so);

add(EAST, ea);

add(WEST, we);

show();

}

Figure 2

Capturing and Displaying Applet Events

import java.awt.*;

import java.applet.*;

import java.net.*;

public class Evlab extends Applet {

public static final String NORTH = "North";

public static final String SOUTH = "South";

public static final String EAST = "East";

public static final String WEST = "West";

TextArea tfe;

public void init() {

setLayout(new BorderLayout());

Button no = new Button(NORTH);

Button ea = new Button(EAST);

Button we = new Button(WEST);

TextField tff = new TextField("", 70);

Font fo = new Font("TimesRoman", Font.BOLD, 14);

tfe = new TextArea(10, 70);

tfe.setEditable(false);

tfe.setFont(fo);

tff.setFont(fo);

add("Center", tfe);

add(SOUTH, tff);

add(NORTH, no);

add(EAST, ea);

add(WEST, we);

show();

}

public void start() {

}

public void stop() {

}

public boolean action(Event ev, Object arg) {

tfe.setText("Id = " + ev.id + "

");

tfe.appendText("x,y = " + ev.x + "," + ev.y + "

");

tfe.appendText("target = " + ev.target.toString() + "

");

tfe.appendText("arg = " + ev.arg + "

");

tfe.appendText("Object = " + arg.toString());

return(false);

}

}

figure 3:

Figure 4

Graphical components and Global elements of the Java AWT

AWT Components

Button Canvas Checkbox CheckboxGroup

Choice Dialog FileDialog Frame

Label List Menu MenuBar

MenuItem Panel Scrollbar TextArea

TextField Window

AWT Global Elements

Color Dimension Font FontMetrics

Graphics Image Insets MediaTracker

Point Polygon Rectangle

Figure 5

A VCR animation applet in Java

/**

A VCR in Java

@author Mark C. Reynolds

@version 1.0, 23 Feb, 1996

*/

import java.applet.*;

import java.awt.*;

import java.net.*;

public class Vcr extends Applet implements Runnable {

MediaTracker tracker;

Dimension nodim;

Thread animthread = null;

Image imgs[];

static final String FWD = "FWD";

static final String REV = "REV";

static final String STOP = "STOP";

static final String EJECT = "EJECT";

int whichimg = 0;

int imginc = 0; // +1 = forward, -1 = reverse, 0 = stop

int nimgs = 0;

boolean done = false;

public void init() {

BorderLayout nl;

FlowLayout fl;

Button bu[];

Font fo;

Panel so;

Panel no;

String tmp;

String imgloc;

imgloc = getParameter("imgloc");

if ( imgloc != null ) {

tmp = getParameter("nimgs");

if ( tmp != null ) {

nimgs = Integer.parseInt(tmp);

if ( nimgs > 0 ) {

imgs = new Image[nimgs];

tracker = new MediaTracker(this);

for(int i = 0, j = 1; i < nimgs; i++, j++) {

imgs[i] = getImage(getDocumentBase(), imgloc + j + ".g

if");

tracker.addImage(imgs[i], 0);

}

nl = new BorderLayout();

setLayout(nl);

no = new Panel();

nodim = preferredSize();

no.resize(nodim.width, nodim.height-50);

add("North", no);

so = new Panel();

fl = new FlowLayout(FlowLayout.LEFT);

so.setLayout(fl);

add("South", so);

bu = new Button[4];

bu[0] = new Button(Vcr.FWD);

bu[1] = new Button(Vcr.REV);

bu[2] = new Button(Vcr.STOP);

bu[3] = new Button(Vcr.EJECT);

fo = new Font("Helvetica", Font.PLAIN, 14);

for(int i = 0; i < 4; i++)

bu[i].setFont(fo);

so.add(bu[0]);

so.add(bu[1]);

so.add(bu[2]);

so.add(bu[3]);

}

}

}

}

public void run() {

Thread me;

if ( nimgs < 1 imgs == null ) return;

try {

tracker.waitForID(0);

} catch (InterruptedException e) {

return;

}

me = Thread.currentThread();

me.setPriority(Thread.NORM_PRIORITY-1);

while ( animthread != null ) {

whichimg += imginc;

if ( whichimg < 0 )

{

whichimg = 0;

imginc = 0;

}

if ( whichimg >= nimgs )

{

whichimg = (nimgs - 1);

imginc = 0;

}

if ( imginc != 0 ) repaint();

try {

Thread.sleep(100);

} catch (InterruptedException e) {

break;

}

}

}

public void paint(Graphics g) {

if ( done == false ) {

if ( ( imgs != null ) && ( 0 <= whichimg ) && ( whichimg < nimgs ) &

&

( imgs[whichimg] != null ) ) {

g.drawImage(imgs[whichimg], 0, 0, this);

}

} else {

g.clearRect(0, 0, nodim.width, nodim.height);

}

}

public void start() {

if ( animthread == null ) {

animthread = new Thread(this);

animthread.start();

}

}

public void stop() {

if ( animthread != null ) {

animthread.stop();

animthread = null;

repaint();

}

}

public boolean action(Event evt, Object arg) {

Button thebut;

String thelab;

boolean handled = false;

if ( evt.target instanceof Button ) {

thebut = (Button)(evt.target);

thelab = thebut.getLabel();

if ( thelab.equals(Vcr.FWD) ) {

imginc = 1;

handled = true;

} else if ( thelab.equals(Vcr.REV) ) {

imginc = (-1);

handled = true;

} else if ( thelab.equals(Vcr.STOP) ) {

imginc = 0;

handled = true;

} else if ( thelab.equals(Vcr.EJECT) ) {

imginc = 0;

done = true;

stop();

handled = true;

}

}

return(handled);

}

}

Figure 5

/**

A VCR in Java

@author Mark C. Reynolds

@version 1.0, 23 Feb, 1996

*/

import java.applet.*;

import java.awt.*;

import java.net.*;

public class Vcr extends Applet implements Runnable {

MediaTracker tracker;

Dimension nodim;

Thread animthread = null;

Image imgs[];

static final String FWD = "FWD";

static final String REV = "REV";

static final String STOP = "STOP";

static final String EJECT = "EJECT";

int whichimg = 0;

int imginc = 0; // +1 = forward, -1 = reverse, 0 = stop

int nimgs = 0;

boolean done = false;

public void init() {

BorderLayout nl;

FlowLayout fl;

Button bu[];

Font fo;

Panel so;

Panel no;

String tmp;

String imgloc;

imgloc = getParameter("imgloc");

if ( imgloc != null ) {

tmp = getParameter("nimgs");

if ( tmp != null ) {

nimgs = Integer.parseInt(tmp);

if ( nimgs > 0 ) {

imgs = new Image[nimgs];

tracker = new MediaTracker(this);

for(int i = 0, j = 1; i < nimgs; i++, j++) {

imgs[i] = getImage(getDocumentBase(), imgloc + j + ".g

if");

tracker.addImage(imgs[i], 0);

}

nl = new BorderLayout();

setLayout(nl);

no = new Panel();

nodim = preferredSize();

no.resize(nodim.width, nodim.height-50);

add("North", no);

so = new Panel();

fl = new FlowLayout(FlowLayout.LEFT);

so.setLayout(fl);

add("South", so);

bu = new Button[4];

bu[0] = new Button(Vcr.FWD);

bu[1] = new Button(Vcr.REV);

bu[2] = new Button(Vcr.STOP);

bu[3] = new Button(Vcr.EJECT);

fo = new Font("Helvetica", Font.PLAIN, 14);

for(int i = 0; i < 4; i++)

bu[i].setFont(fo);

so.add(bu[0]);

so.add(bu[1]);

so.add(bu[2]);

so.add(bu[3]);

}

}

}

}

public void run() {

Thread me;

if ( nimgs < 1 imgs == null ) return;

try {

tracker.waitForID(0);

} catch (InterruptedException e) {

return;

}

me = Thread.currentThread();

me.setPriority(Thread.NORM_PRIORITY-1);

while ( animthread != null ) {

whichimg += imginc;

if ( whichimg < 0 )

{

whichimg = 0;

imginc = 0;

}

if ( whichimg >= nimgs )

{

whichimg = (nimgs - 1);

imginc = 0;

}

if ( imginc != 0 ) repaint();

try {

Thread.sleep(100);

} catch (InterruptedException e) {

break;

}

}

}

public void paint(Graphics g) {

if ( done == false ) {

if ( ( imgs != null ) && ( 0 <= whichimg ) && ( whichimg < nimgs ) &

&

( imgs[whichimg] != null ) ) {

g.drawImage(imgs[whichimg], 0, 0, this);

}

} else {

g.clearRect(0, 0, nodim.width, nodim.height);

}

}

public void start() {

if ( animthread == null ) {

animthread = new Thread(this);

animthread.start();

}

}

public void stop() {

if ( animthread != null ) {

animthread.stop();

animthread = null;

repaint();

}

}

public boolean action(Event evt, Object arg) {

Button thebut;

String thelab;

boolean handled = false;

if ( evt.target instanceof Button ) {

thebut = (Button)(evt.target);

thelab = thebut.getLabel();

if ( thelab.equals(Vcr.FWD) ) {

imginc = 1;

handled = true;

} else if ( thelab.equals(Vcr.REV) ) {

imginc = (-1);

handled = true;

} else if ( thelab.equals(Vcr.STOP) ) {

imginc = 0;

handled = true;

} else if ( thelab.equals(Vcr.EJECT) ) {

imginc = 0;

done = true;

stop();

handled = true;

}

}

return(handled);

}

}

Figure 6

The HTML file which drives the Java VCR

<HTML>

<HEAD>

<title>A Java VCR</title>

</HEAD>

<BODY>

<HR>

<APPLET CODE="Vcr.class" WIDTH=300 HEIGHT=150>

<PARAM NAME=imgloc VALUE="images/T">

<PARAM NAME="nimgs" VALUE="16">

</APPLET>

<HR>

<A HREF="Vcr.java">The source.</A>

</BODY>

</HTML>

figure 7

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有