Java Swing Graphics Basics
In this lesson we introduce graphics in Java.
Obviously GUIs
are graphics, so what are we doing now
that's different? Well, in the GUI programming we've done so
far, the GUI components (e.g. JButton, JLabel, JFrame, ...)
have drawn themselves. Now
our code will do the
drawing. However, the mechanism for drawing is actually the
same, whether it's done by API code or by our own code.
In Java's Swing library, all drawing is done by
callback methods. In otherwords, a
JComponent-extending class that
wants itself drawn overrides the JComponent method
protected void paintComponent(Graphics g);
and the Event Dispatch Thread will call that method whenever
it deems that the component needs to be drawn. When would
that happen?
-
A system event, like a window being resized, uncovered,
etc. could cause the Event Dispatch Thread to call
paintComponent.
-
Some code in your program might call your component's
repaint() method, which will cause the Event Dispatch
Thread to, at its earliest convenience, call your
componenet's paintComponent method.
-
Some code in your program might call repaint() on a
componenet that contains your componenet, which will cause the Event Dispatch
Thread to, at its earliest convenience, call that
container's paintComponenet method, which will in turn
call the paintComponent methods of the components it
contains.
The Graphics g parameter to paintComponent is the
thing you use to do the actual drawing. It has methods for
drawing rectangles, ellipses, ... , text and images.
Overriding paintComponent
According to the above, all we have to do to draw on a
componenet is to override its paintComponent method. So
... let's do that!
In this example, the only thing that's new is that we've
overridden this "paintComponenet" method that we were
previously unaware of. Notice that we call
super.paintComponent(g) first. That paints the button in the
usual fashion, then we go and paint our stuff on top of it.
Graphic2D and the awfulness of backwards compatibility
Now I'm going to throw a wrench into the works. At some point
Java improved its graphics API, but it didn't want to get rid of
the earlier stuff (for backwards compatibility reasons), so
... they derived a new class Graphic2D from Graphics, and the
argument paintComponent gets sent is actually of that new type.
However, you have to cast g to Graphics2D explicitly.
For us, the nice feature of Graphics2D is that there are methods
void draw(Shape s);
void fill(Shape s);
that give you outlined or filled-in versions of any object
derived from class Shape. And, of course, the API has
Shape-derived objects for rectangles and ellipses and lines and more
exotic things as well.
Here's the exact same program as before, but done with
Graphics2D calls.
Some of the many different graphics operations
Of course you wouldn't normally draw over a JButton, as we did
in the previous examples. You can draw on any JComponent. If
you just want a blank space to draw on, you can just extend
the base JComponent class. In the example below, we define a
DrawArea in this way, and we show off some of the many things
you can do with Java graphics. (Note: we use the file
catr.png)
Animation and mouse events
This last example is given to you with no real explanation. You
should, in fact, be able to follow it. The gist is this:
animation is nothing more than having a thread that changes
something about your scene, and calls repaint() periodically to
draw the new version of the scene.