![]() |
|
FREE
ONLINE COURSES FOR THE INTERNET COMMUNITY
|
|
Chapter 3: Threads and animation Chapter 4: Images and parameters |
The applet will be a thread based applet with start() and stop() methods which you can read more about in section 3.0.1. The Run() method looks almost the same as in the textscroller example in chapter 3: public void run() { while (true) { update(getGraphics()); //"currentimage" is increased so that the next //image is displayed in the next screen update. currentimage++; //However, "currentimage" must not exceed the //index value of 3. if (currentimage>3) currentimage=0; try {Thread.sleep(200);} catch(InterruptedException e) {} } } The only change we have made in the textscroller's run() method is the handling of the "currentimage" variable. This variable will be used as index so that the applet will change image every 200 millisecond (5 times per second). The paint() method will look like this: public synchronized void paint(Graphics g) { //The integer "currentimage" is used as //index for the "images" array. g.drawImage(images[currentimage],0,0,this); } The images we will animate look like this:
The result of the animation will be that the arrow will appear to being rotated. This is not very interesting to see and we will in a later chapter review how we can do this with only one image and using image processing. Click here to see the applet. The Java language would never have had such a big breakthrough on the Internet if it had not been for the possibility to configure Java applets. Without configurable Java applets, the Java technology would have stayed at the hands of the developers and never got to the web designers. The applet parameters is what makes an applet recyclable and available for everybody. It is a glorious feeling to randomly surf into a homepage that is using the applet that you have developed and reconfigurated. With parameters you can change almost anything in an applet such as the images used, colors, texts, font styles and more. Parameters also simplify your work as a programmer due to the simplicity to change parameter values and not having to change variables directly in the source code. 4.1.1 Working with getParameter() It is very simple to read a parameter. Look at the following HTML code: <APPLET CODE="myapplet.class" WIDTH=200 HEIGHT=100> <PARAM name="myparameter" value="Long live Java!"> </APPLET>
In HTML, PARAM is used to specify a parameter, where "name" stands for the name of the parameter and "value" for the content. The method getParameter() always return a String and can, for instance, fetch "myparameter" like this: String oneparameter=getParameter("myparameter"); Now "oneparameter" will contain the phase "Long live Java!". You may have how many parameters as you like, theoretically. However note that each parameter must have an unique name label. To simplify your work and to make your source code easy to read you should always read parameters in the init() method. The alternative is to put these lines in the run() method which will make your code difficult to read. 4.1.2 How to read an integer as a parameter (getIntegerParameter()) As we saw in the last section, getParameter() always return a string. If you want to read an integer instead, then you can use the following method: public int getIntegerParameter(String name, int base) { String value=getParameter(name); int intvalue; try {intvalue=Integer.parseInt(value,base);} catch (NumberFormatException e) {return 0;} return intvalue; } The method above is always good to have in an configurable applet, so you should always have the habit of pasting these lines into your source code, if you are going to make such an applet. The Integer class in Java is used to handle integers, but please note carefully now: "Integer" is NOT the same as "int". Integer is a class with methods while int is just a data type. A useful method that Integer has, is the static method parseInt() that converts a String to an integer ("int"). The other argument in parseInt() is the number base that may be decimal or hexadecimal (number base 10 or 16 respectively). The decimal number base is the normal number base system you use on your everyday life. If you are a web designer then you should also know the hexadecimal number system when you specify colors (that is if you write the HTML code yourself without a graphical HTML editor). You will later see the use of this when we specify colors for the textscroll applet. 4.1.3 AppletAnimator II, now configurable There are not many changes that must be done in the AppletAnimator applet from section 4.0.4 to make it configurable. We start by adding a variable, "maxitems", which will indicate the number of images the user has specified in the applet parameters. The value for this variable must be specified by the user as a parameter, the name will also be called "maxitems": //"maxitems" will be used to indicate the number of //images that exist. int maxitems=0; //"sleeptime" indicates the delay between each image //in milliseconds. int sleeptime=0; Image images[]; int currentimage=0; public void init() { ///Get the value of the parameter "maxitems" //with the number base 10. maxitems=getIntegerParameter("maxitems",10); /Get the value of the parameter "sleeptime". sleeptime=getIntegerParameter("sleeptime",10); //The array "images" will have "maxitems" number //of elements. images=new Image[maxitems]; MediaTracker tracker=new MediaTracker(this); for (int i=0; i<maxitems; i++) { //The following line will read the values of the //parameters "image0", "image1", "image2" and so on //up to the value that maxitems indicates. It will also //use the strings to load the files specified in those //parameters. images[i]=getImage(getDocumentBase() ,getParameter("image"+i)); //The ID number for each image must be increased //for each image you add to the tracker. tracker.addImage(images[i],i); } //Finally we make sure that the tracker loads the images. try {tracker.waitForAll();} catch(InterruptedException e) { System.out.println("Something happened while reading images..."); } } The applet will start first by reading the value of "maxitems". This variable must contain the exact number of image parameters that will be read by the applet. The variable "sleeptime" indicates the delay between each image frame, which may be very useful to implement. The file name for each image is specified in the parameters "image0", "image1" and so on. What happens is that the for loop reads a parameter and directly uses it's value to load the image file and adds it to the tracker's list. The configuration for getting the same effect as the example in section 4.0.4 would then look like this: <APPLET CODE="appletanimator2.class" WIDTH=100 HEIGHT=100> <PARAM name="maxitems" value="4"> <PARAM name="sleeptime" value="200"> <PARAM name="image0" value="image0.gif"> <PARAM name="image1" value="image1.gif"> <PARAM name="image2" value="image2.gif"> <PARAM name="image3" value="image3.gif"> </APPLET> The applet is not yet ready. We need to make two small changes in the run() method: public void run() { while (true) { update(getGraphics()); //"currentimage" is increased so that the next //image is displayed in the next screen update. currentimage++; //However it must not exceed the value //of maxitems minus 1. if (currentimage>maxitems-1) currentimage=0; //The variable sleeptime sets //the delay in milliseconds. try {Thread.sleep(sleeptime);} catch(InterruptedException e) {} } } Please note that "maxitems-1" is the upper limit for the "currentimage" variable and the delay is now set by the "sleeptime" variable. At last it is time to present our first configurable applet! To demonstrate how the same applet can be reconfigurated and look completely different, we use it as a simple slide show with six texture images. We do this by increasing the delay to 2000 milliseconds (2 seconds) and setting "maxitems" to 6. Click here! 4.1.4 A configurable and effectfull image slide show (SlideShow) Even if AppletAnimator II can be used to display images, yet it is not very impressive. We will now develop an animated slide show that slowly translates an image from a random location until it covers the old image completely. At last we are about to use random numbers. There is a very useful class in Java which is called Math. This class contains mostly static methods, so you do not have to create a Math-object to use these, you can call them directly. A very important method is the random() method. It returns a double floating point random number between 0 and 0.9999999... By multiplying with 10, you could get random numbers between 0 and 9. Please note that when you type cast a double to an integer, then the number will be rounded to the lowest integer value. Look at the following line: int randomnumber = (int)(Math.random()*2.0); The variable "randomnumber" will be set to 0 or 1. In the slide show we will use random numbers to indicate from what corner an image is going to be translated from. Actually to make this applet, we can just take all the variables and methods in the AppletAnimatorII applet and use these with just one change in the run() and paint() methods. We must also add the following global variables below the declaration of the "currentimage" variable: int nextimage = 0; int nextimagexposition = 0; int nextimageyposition = 0; These variables indicates what image will be animated into the applet screen and what it's current position is. The paint() method will then look like this: public synchronized void paint(Graphics g) { g.drawImage(images[currentimage],0,0,this); //The following image is drawn on top of the last //image. g.drawImage(images[nextimage] ,nextimagexposition,nextimageyposition,this); } The run() method will be a bit more complicated. We must for the first time find out what the applet dimensions are, because the person that will use the applet will probably change the dimensions. You do that with the size() method, which returns a Dimension object. With this object, we can find out the applet dimensions with it's internal variables, "width" and "height". public void run() { //We must find out the applet's dimension and save it //in the "d" variable. We can now get the applet //width and height by writing d.width and d.height. Dimension d=size(); //The "displacement" variables specify the //starting coordinates for the image. int displacementx=0; int displacementy=0; //"pathsize" will be used to know what distance //that the new image will be moved. int pathsize=0; //"currentimage" is initialized to the first image, //followed by the next image, who becomes image //number 2, and so on. The applet begins by placing an image out of visual range of the spectator, that is outside the applet screen. Slowly the image is translated to the center, one pixel at the time. A problem that can appear here, is the case when the applet is a rectangle and not a quadrate. Because then the applet must move the image with different horizontal and vertical steps. Therefore we use the short side of the applet screen and use it in the for loop to count to the number of pixels (the variable "pathsize"). We calculate a percent of how much the image must move (i/pathsize) and multiplicate this with d.width or d.height to get the total horizontal and vertical distance that it has translated and the new x and y position for the image. The problem here is, because we are working with integers, we must make the division last. Therefore we write ((i*d.width)/pathsize) instead. Or else (i/pathsize) will always give the result zero because the value of "pathsize" is larger than "i". This is important, if you divide a smaller integer with a larger integer, then the result is always zero. Finally we must also multiply this expression with "directionx" or "directiony", so that the image moves in the right direction and deduce this expression from "displacementx" and "displacementy" respectively, which are the images start coordinates. The image demonstrates how the slide show works. The new image "nextimage" will be translated over the old image "currentimage". After the for loop, we set "currentimage" to indicate the new image and increase "nextimage" so that it points to the next image in the slide show. If "nextimage" is pointing at the last image, then we set it to zero, so that it points to the first image instead (zero index). The result is that the images will rotate around in the slide show, so that the effect never ends. This line must also be used before the for loop, in the case that the user for some strange reason would like to specify just one image in the applet. This must be done in order to keep the applet from crashing. Now you can look at the result by clicking here. You are disappointed, right? All this trouble just for a flimmering applet! The problem with the applet is, that when the first image has been drawn in the paint() method with drawImage(), then the applet screen is updated immediately. It will therefore fully display the old image before it finds the time to cover it with the next image. We must therefore find a way to prevent the applet screen to be updated between the two drawImage() calls. It is here we will have use for the double buffering technique, which will be discussed in the next section of this chapter. Double buffering is a technique used in almost any programming languages by game and special effect developers. When you draw lines, rectangles, texts and images directly to the screen, then you can in principle see when every object is drawn. This is not good if you only want the spectator to see the end result and nothing more. As we have seen with the textscroller and slideshow examples, this can cause flimmering. To avoid this, you draw first on a buffer (that is why it is called "double buffering"). The buffer is an image that you draw on "in secret" and do not show it to the spectator until it is finished. In Java you do this by creating an image as large as the applet, and then you get a Graphics object connected to this image. When you have finished drawing then you call the paint() method that displays the buffer image on the screen. 4.2.1 SlideShow II, now without flimmering To add double buffering to the slideshow applet in the last section, me must first declare a global Image variable and a Graphics variable that we initialize in the init() method. Add the following variables to the global applet variables (add them under the declaration of the "nextimagepositiony" variable): //"bufferimage" is used as the buffer and //"bufferg" is used to draw on this buffer. Image bufferimage; Graphics bufferg; //"delay" will be used instead of "sleeptime" to //delay the each animation. "sleeptime" will be used to //add a configurable delay between each image instead. int delay=0; Now that we are in the process of changing the applet, we can take the opportunity to add a new parameter, "delay". This variable will be used instead of "sleeptime" as a delay in the animation. The variable "sleeptime" will be used as the pause between each next image instead. Now the user of this applet will be able to specify a delay before the next image is animated. To create the graphics buffer we write the following lines and add them last in the init() method: //Fetch the size for the applet. Dimension d=size(); //createImage() creates an empty image //that has the same dimensions as the //applet screen. bufferimage=createImage(d.width,d.height); //"bufferg" is now associated with the //buffer image. bufferg=bufferimage.getGraphics(); delay=getIntegerParameter("delay",10); The only thing we have to do now is to see to that the two images are drawn in the buffer first and not directly on the screen. This is done in the paint() method: public synchronized void paint(Graphics g) { //First we should check that "bufferg" //is initialized, it is not always sure that it //is. if (bufferg!=null) { //We draw the two images into the buffer first. bufferg.drawImage(images[currentimage],0,0,this); bufferg.drawImage(images[nextimage] ,nextimagexposition,nextimageyposition,this); //Now we draw the buffer image into the applet //screen. g.drawImage(bufferimage,0,0,this); } } There are some changes that must be done in the run() method too, now that we have changed the parameters: public void run() { Dimension d=size(); int displacementx=0; int displacementy=0; int pathsize=0; currentimage=0; nextimage=1; while (true) { int directionx=(int) (Math.random()*3.0)-1; int directiony=(int) (Math.random()*3.0)-1; if (directionx==0 && directiony==0) directiony=1; if (d.width<d.height) pathsize=d.width; else pathsize=d.height; displacementx=directionx*d.width; displacementy=directiony*d.height; if (nextimage>maxitems-1) nextimage=0; for (int i=0; i<=pathsize; i++) { nextimagexposition=displacementx -directionx*(i*d.width)/pathsize; nextimageyposition=displacementy -directiony*(i*d.height)/pathsize; update(getGraphics()); //Now "delay" is the delay in the loop. try {Thread.sleep(delay);} catch(InterruptedException e) {} } //"sleeptime" is used outside the loop. try {Thread.sleep(sleeptime);} catch(InterruptedException e) {} currentimage=nextimage; nextimage++; if (nextimage>maxitems-1) nextimage=0; } } We add a new delay outside the for loop and use the "sleeptime" variable there instead. Now the applet user can specify a delay before the next image starts rolling in. Now the applet should be completely finished. Do not forget to add the HTML parameter "delay" and set this to 20 before testing the applet. Set the parameter "sleeptime" to 1000 milliseconds or more. Click here to look at the applet. Is it not beautiful? 4.2.2 A configurable TextScroller (TextScroller II) As you may remember, the textscroller i chapter 3 was flimmering. We can fix it now that we know the double buffering technique. At the same time we make it more configurable. Let us start by adding and modifying some variables first: public Thread animationthread = null; public String message; public int x=100; Image bufferimage; Graphics bufferg; //The following colors are fetched as //HEXADECIMAL parameters and are used //to set the background and text color //of the applet. Color backgroundcolor,textcolor; //The "delay" variable is used as a delay //for each picture frame. int delay=0; We have added some variables to set the background and foreground colors. The "delay" variable will be the delay in the animation, as it was in the slideshow applet. Do not forget to paste the getIntegerParameter() method. The init() method must also be altered a bit: public void init() { //We read the message as a parameter instead at the same //time as we read a paramter called "delay" for the //picture delay. message=getParameter("message"); delay=getIntegerParameter("delay",10); //Please note that we read the values in //HEXADECIMAL form (with the base 16) //and then create a color. backgroundcolor= new Color(getIntegerParameter("backgroundcolor",16)); textcolor=new Color(getIntegerParameter("textcolor",16)); //The following lines are just copied from //slideshow2.java Dimension d=size(); bufferimage=createImage(d.width,d.height); bufferg=bufferimage.getGraphics(); } Please note that we get the colors for the applet with the getIntegerParameter() method and specifying that we want to read them in the number base 16, instead of 10. This is done so that these parameters can be specified with hexadecimal numbers by the applet user. The parameters could then look like this: <APPLET CODE="textscroller2.class" WIDTH=100 HEIGHT=20> <PARAM name="message" value="This is textscroller II, now configurable"> <PARAM name="backgroundcolor" value="ff0000"> <PARAM name="textcolor" value="0000ff"> <PARAM name="delay" value="50"> </APPLET> We have set the background color to red (FF0000) and the text color to blue (0000FF). If you are not used to hexadecimal color values then maybe the following table may be useful:
All the drawing in the paint() method must be done in the buffer, instead of directly in the applet screen. When it is finished, then the buffer is displayed on the screen: public synchronized void paint(Graphics g) { //It is always a good idea to check //that bufferg has been initialized. if (bufferg!=null) { //Paint the screen with the fetched //background color. bufferg.setColor(backgroundcolor); bufferg.fillRect(0,0,100,20); //Draw the message starting from //position "x". bufferg.setColor(textcolor); bufferg.drawString(message,x,12); g.drawImage(bufferimage,0,0,this); if (x<-400) x=100; x--; } } Note that we use the variables "backgroundcolor" and "textcolor" to specify the background color and the text color for the applet. Finally we make a small change in the run() method so that the frame delay for the applet can be set: public void run() { while (true) { update(getGraphics()); //The "delay" variable now makes //the delay configurable. try {Thread.sleep(delay);} catch(InterruptedException e) {} } } Now the applet is ready. You should know that the text's length is limited and the applet dimensions must be 100x20 pixels. It does not make sense to change the dimensions right now, when you cannot control the text size anyway. You will learn this in chapter 6. Click here to see the applet. Now you may feel ready to start your own Java company and flood the Internet with your applets, after this chapter. You would even now manage rather well as a special effects programmer, but there are some pieces left in your education. Some of them we will review in the next chapter which is about mouse messages.
Copyright © 1999-2005 Mandomartis Software Company
|
|