Proper (vs. desirable) use of Graphics object

W

Wolfgang

I have been using a JPanel with a graphics object to draw lines, etc.,
like this:

private class DrawingPanel extends JPanel {
public void paint(Graphics g) {
x = 10; y = 20;
g.drawString("someText", x, y);
// draw all my graphics here...
// which means all calculation of coordinate
// locations x and y has to go here.
// I DON'T LIKE THAT, it causes clutter..
}
}

The above way of drawing is somewhat alien to me. I think of drawing
more like calculating some positions, than passing them to a drawing
method in a drawing object (something like a DrawingPanel). Java's
design of the Graphics class seems to disallow my preference, or I
cannot see a way to perform my simple "classical" way of drawing,
since I cannot pass coordinate locations for drawing into
DrawingPanel.paint.

Am I overlooking somthing simple here? If so, how can you do this?

Thanks,
Wolfgang
 
C

Chris Smith

Wolfgang said:
I have been using a JPanel with a graphics object to draw lines, etc.,
like this:

private class DrawingPanel extends JPanel {
public void paint(Graphics g) {
x = 10; y = 20;
g.drawString("someText", x, y);
// draw all my graphics here...
// which means all calculation of coordinate
// locations x and y has to go here.
// I DON'T LIKE THAT, it causes clutter..
}
}
Okay...

The above way of drawing is somewhat alien to me. I think of drawing
more like calculating some positions, than passing them to a drawing
method in a drawing object (something like a DrawingPanel).

I'm not entirely clear on what you mean, so I apologize in advance if
I've misinterpreted you.

DrawingPanel is not "a drawing object". It's a component. It just
happens to have the behavior of drawing itself, among *many* other
things. If you want to encapsulate the drawing process itself in an OO
way, nothing is preventing you from doing so. Something like:

interface Drawable
{
public void draw(Graphics g, int x, int y);
}

public class DrawableSprite implements Drawable
{
...
}

public class DrawingPanel extends JPanel
{
public void paint(Graphics g)
{
int x = 10;
int y = 20;

new DrawableSprite().draw(g, x, y);
}
}

Is that what you mean by "calculate some positions, then pass them to a
drawing method in a drawing object"?
Java's design of the Graphics class seems to disallow my preference, or I
cannot see a way to perform my simple "classical" way of drawing,
since I cannot pass coordinate locations for drawing into
DrawingPanel.paint.

You never call paint anyway, so no you can't pass coordinates for it.
The paint method is responsible for painting the whole component, so it
wouldn't really make sense for any coordinates to be passed. If I had a
clearer idea of how you want this to work (or maybe what I wrote above
is it?) then perhaps I could give a better answer.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Ryan Stewart

Wolfgang said:
I have been using a JPanel with a graphics object to draw lines, etc.,
like this:

private class DrawingPanel extends JPanel {
public void paint(Graphics g) {
x = 10; y = 20;
g.drawString("someText", x, y);
// draw all my graphics here...
// which means all calculation of coordinate
// locations x and y has to go here.
// I DON'T LIKE THAT, it causes clutter..
}
}

The above way of drawing is somewhat alien to me. I think of drawing
more like calculating some positions, than passing them to a drawing
method in a drawing object (something like a DrawingPanel). Java's
design of the Graphics class seems to disallow my preference, or I
cannot see a way to perform my simple "classical" way of drawing,
since I cannot pass coordinate locations for drawing into
DrawingPanel.paint.

Am I overlooking somthing simple here? If so, how can you do this?

What Chris said plus: You can pass the Graphics objects to other objects to
let them draw on it. Instead of having one long paint method (or render
method as I usually make it--depends on what you're doing) to calculate and
draw every little thing, go the OO route. Recently I've been working on
coding a Scrabble applet. My main class is the applet. I have a Board class
and a Rack class and a Tile class for all the letters that go on both the
board and the rack. There's other stuff as well, but consider just those two
for the moment. It's quite possible that there could be 50, 60, or more
tiles out on the board and rack at the same time. Am I going to draw all
those from the applet's paint method? Of course not. For drawing the board
and rack:
board.render(g);
rack.render(g);

where g is the Graphics object. Then the board draws itself and calls:
tile.render(g);

for each tile on it. The rack does the same thing. So each object is fully
encapsulated, including its drawing routines. Only a tile knows what it
looks like, and it's the only one that needs to.
 
A

Andrew Thompson

| | > I have been using a JPanel with a graphics object to draw lines, etc.,
| > like this:
...

|.... You can pass the Graphics objects to other objects to
| let them draw on it. Instead of having one long paint method (or render
| method as I usually make it--depends on what you're doing) to calculate
and
| draw every little thing, go the OO route.

Like this?
http://www.physci.org/launcher.jsp#DoubleBufferedAnimateFrame

5 Balls [line 157] are instantiated,
and they draw themselves on the
graphics object..[l. 175]
 
S

Sudsy

Wolfgang wrote:
Am I overlooking somthing simple here? If so, how can you do this?

What you appear to be missing is one of the basic concepts of OOP.
You send messages to objects instructing them to perform operations.
The results will not necessarily be returned to the invoker. You
might be able to query the object for the results but it doesn't
have to be a synchronous operation.

From the javadocs for java.awt.Component:
"A component is an object having a graphical representation that
can be displayed on the screen and that can interact with the user."

A component must know how to paint itself. IOW, I hand a component
a Graphics context and it's up to that component to render itself
into the drawing area.
It sounds weird if you're not used to it but there are tons of on-
line examples and tutorials which cover this. I'd start at Sun
(<http://java.sun.com/docs/books/tutorial>).
 
R

Ryan Stewart

Andrew Thompson said:
| | > I have been using a JPanel with a graphics object to draw lines, etc.,
| > like this:
..

|.... You can pass the Graphics objects to other objects to
| let them draw on it. Instead of having one long paint method (or render
| method as I usually make it--depends on what you're doing) to calculate
and
| draw every little thing, go the OO route.

Like this?
http://www.physci.org/launcher.jsp#DoubleBufferedAnimateFrame

5 Balls [line 157] are instantiated,
and they draw themselves on the
graphics object..[l. 175]

Yes, like that. :)
 
T

Thomas Weidenfeller

Wolfgang said:
I have been using a JPanel with a graphics object to draw lines, etc.,
like this:

private class DrawingPanel extends JPanel {
public void paint(Graphics g) {

Use paintComponent(), not paint() in Swing.
The above way of drawing is somewhat alien to me. I think of drawing
more like calculating some positions, than passing them to a drawing
method in a drawing object (something like a DrawingPanel).

Swing and AWT use something like a callback mechanism for painting. You
are not supposed to "push" graphics to the output. Instead, you are
supposed to wait until Swing/AWT ask you to draw something. When
Swing/AWT see the need to (re)draw some parts, the paint[Component]()
method is called. This is Swing's/AWT's way of asking you to paint
something. "Don't call us, we will call you!".

This mechanism is necessary due to the way some GUI systems work. In
fact, it is a 1:1 mapping of how some of this systems work. E.g. X11
without backing store enabled, doesn't save the parts of a window which
are obscured by other windows. So once the obscured parts are supposed
to become visible again (window is moved, or brought to the front), the
GUI system has to ask the application to redraw that particular part of
the window. This request from the GUI system ends up in some native JVM
code, and is (via a few intermediate steps) transfered to a call of the
paint[Component]() method.
Java's
design of the Graphics class seems to disallow my preference,

They can't allow it. Otherwise it would be difficult or inefficient to
support GUI systems that work as described above.
or I
cannot see a way to perform my simple "classical" way of drawing,
since I cannot pass coordinate locations for drawing into
DrawingPanel.paint.

Solution A - Most suitable for vector graphics:

Use a simple list, or whatever data structure suits your needs. In this
list, store the drawing operations you would like to perform. Inside
paintComponent() iterate through that list, and execute the operations.

The java.awt.gemo objects are good candidates for being the elements of
such a list.

You can apply some optimization by observing the clipping region of the
provided Graphics[2D] object, and having a data structure which allows
for a quick decision if some geometry object falls completely outside of
the clipping region.

Solution B - Most suitable for bitmap graphics:

Do all your drawing to a separate image, like a BufferedImage. Within
the paint[Component]() method you just copy the relevant parts from your
BufferedImage to the provided Graphics[2D]. Again, you can optimize by
observing the clipping region. You might also turn of Swing's internal
double-buffering, since you are now buffering yourself.

In both cases, have an eye on threading issues.

Things you shouldn't do:

Don't use getGraphics() to obtain a Graphics[2D] object from outside of
paint[Component](). getGraphics() can return null, but, more important,
you drawings will be corrupted on GUI systems like the one described
above, because you don't repaint it when the GUI system needs it.

/Thomas
 
D

Dale King

Wolfgang said:
I have been using a JPanel with a graphics object to draw lines, etc.,
like this:

private class DrawingPanel extends JPanel {
public void paint(Graphics g) {
x = 10; y = 20;
g.drawString("someText", x, y);
// draw all my graphics here...
// which means all calculation of coordinate
// locations x and y has to go here.
// I DON'T LIKE THAT, it causes clutter..
}
}

The above way of drawing is somewhat alien to me. I think of drawing
more like calculating some positions, than passing them to a drawing
method in a drawing object (something like a DrawingPanel). Java's


In addition to the other fine answers, on the subject of calculating
coordinates that is not really the best way to do things in the world of
Java2D.

Say you had a shape that could move around in different positions and/or be
different sizes. Instead of recalculating the coordinates of the points
yourself, instead you have define how it is drawn using any convenient
coordinate system for your purposes and then instead of modifying your
values you tell the Graphics2D object (its a subclass of Graphics and that
is what is actually passed to you) to change its coordinate system so that
it will transform from your coordinates to the proper on-screen coordinate
system using an AffineTransform.

Instead of actually drawing complex shapes as a series of graphics
primitives calls you can also define the shape using some implementation of
java.awt.Shape.

I suggest studying the Java 2D tutorial:
http://java.sun.com/docs/books/tutorial/2d/index.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top