Site icon IT World Canada

Java gets the full picture

The trouble with starting a series of columns is that you have to finish it, and every attempt to write something, anything for this final instalment has only led me to wallow in the doldrums of writer’s block.

So I turned to my usual source of inspiration: loud rock music. To be specific, the new CD from local band Attomik. While the first few bars of distorted guitar rattled my home, I looked at the album cover and could have sworn one of those cartoon light bulbs actually appeared above my head. The lead singer is pictured wearing a virtual reality visor, while the “real” world around him is rendered in computer graphics. Trippy, I know. But a computer graphic world – now there’s something I can write about. In a way, we all know what it’s like to live in one.

Raise your hand if you spend more hours during the day looking at your monitor than at your family. It only seems fair, then, to demand a high standard of aestheticism from your applications. For those of us creating the applications, we’d be wise to keep in mind that if they are to be well received they must look as cool as they behave.

Stellar language that it is, Java provides us with all the tools we need to create and manipulate graphics. Let’s begin with the Graphics Object.

The Graphics Object is one of those things that cause many a student to say, “Java is hard, man.” This is because the Graphics class is abstract. So how can an object of that type get passed to the typical paint() method shown here?:

public void paint (Graphics g) {}

It has to do with that polymorphism thing I’ve been ranting about, and it has to do with Java’s portability across platforms. Drawing to the screen is a different process on a Mac, for instance, than it is on a PC. Therefore, the paint() method depends on the dynamic creation of an object that extends Graphics with system-specific instructions for screen output. This is handled by the system, so I am content to believe it is magic. If you’re ambitious enough to want more info on the topic, you’ll have to consult your friendly neighbourhood propellerhead/Java pundit. What matters to us is what we do with the Graphics Object once our paint() method receives it.

The Graphics Object has methods for drawing shapes, displaying images, etc., but there are enough resources out there devoted to such banal subject matter. More in line with the “concepts” initiative of this series is the interplay between the class containing the paint() method and objects that contain the code to draw themselves. The following code snippets are taken from a fun little application I had to do for school, in which I made an ant and a termite run around on the screen (yes, this was really an assignment):

This is the paint() method that the application uses to draw to the screen:

public void paint ( Graphics g ){

//fill the entire panel (from cords 0,0 to the width and height

//of the panel) in with white

g.setColor(Color.white);

g.fillRect(0,0,super.getWidth(),super.getHeight());

//call each object’s draw method, passing the

//Graphics Object

ant.draw(g);

termite.draw(g);

}

This is the draw() method for the Ant Object:

public void draw(Graphics g){

//antImage is an Image Object defined as the graphic of the ant,

//oriented based on the direction it’s currently walking in.

//x and y are the coordinates to draw the ant at

g.drawImage(antImage, x, y, null);

}

When the paint() method passes the Graphics Object to the draw() methods of the other classes, it is giving them the information they need to draw themselves on that particular system.

A common practice for applications that do a lot of screen refreshing is double buffering. Double buffering reduces flicker by dumping everything that is to be displayed onto a single Image Object, and then drawing that Image Object to the screen all at once.

Here is the above paint() method rewritten to implement double buffering:

public void paint ( Graphics g ){

//declare a Graphics Object and Image Object

Graphics offScreenGraphics;

Image offScreenImage = null;

//set the buffer image (offScreenImage) to the width and height of the panel

offScreenImage = createImage(super.getWidth(), super.getHeight());

//the new Graphics Object gets its context from the buffer image

offScreenGraphics = offScreenImage.getGraphics();

//draw to the buffer image using the new Graphics Object

offScreenGraphics.setColor(Color.white);

offScreenGraphics.fillRect(0,0,super.getWidth(),super.getHeight());

ant.draw(offScreenGraphics);

termite.draw(offScreenGraphics);

//now use the Graphics Object from the system to draw the

//complete buffer image

g.drawImage(offScreenImage,0,0,null);

}

As this series draws to a close, I’d like to leave you with some closure, some final words of wisdom. The best I could come up with is, “Java is not hard, man.” If there’s one unifying idea I’ve tried to illustrate, it’s that the language itself is nothing but a series of concepts. No one can possibly know all there is to know about code writing syntax, but if you grasp the logic that holds it all together, then you can easily learn the details as you go along. And if you should get stuck for ideas, there’s always loud rock music.

Cooney is a Toronto-based programmer and a freelance Internet developer. He is currently enrolled in Humber College’s Computer Programmer program. He can be reached at robert_cooney@hotmail.com.

Exit mobile version