Unable to paint (using paint() in JPanel) inside mouse listeners

E

eshedz

[ this post is equal to
http://forum.java.sun.com/thread.jspa?threadID=675471&tstart=0]



This is hard to explain but I'll do my best :)

I've created a little game and at some point I needed to make images
"move" on the JPanel (through paint()), on a checkers-based game board.

The game works like so:
it has a mouse listener for clicks and movement, and the main game
process is THINK(), REPAINT(), which is repeated until the user wins
(the above is inside a while).
The mouse actions were added to the constructor so they are always
active, THINK changes the enemy's locations, and REPAINT simply calls
"paint()" again.

The picture is either an enemy or the player, and it can only "rest" on
squares.
(e.g. point's x and y must be divided in 50).

While doing that, I wanted to make the movement more sleek and clean,
instead of them simply jumping from one square to the other with a
blink of the eye.

So, I've created MOVEACTOR, that "moves" an enemy or a player from its
current point (actor.getPoint()) to the requested future square
(futurePoint).

//actor = enemy or player, has getPoint() that returnes the current
point on the board where he rests on.
//futurePoint = the new point where the enemy or player should be after
the animation.
//please ignore obvious stuff that has nothing to do with what I asked
-- those will be deleted in the future, for they are only temporary
checking extra lines and stuff.
//also feel free to ignore the "jumpX" things. Those are just to change
images, to imitate physical "jumping" animation.

protected void moveActor(Actor actor, Point futurePoint)
{
Point presentPoint = actor.getPoint();

int x = (int)presentPoint.getX(), y = (int)presentPoint.getY();
int addToX, addToY;

if (futurePoint.getX() > x) addToX = 1;
else addToX = -1;
if (futurePoint.getY() > y) addToY = 1;
else addToY = -1;

Point middlePoint = new Point(x,y);

int imageCounter = 0;

while ( (middlePoint.getX()!=futurePoint.getX()) &&
(middlePoint.getY()!=futurePoint.getY()) ){
imageCounter++;
x+=addToX;
y+=addToY;
middlePoint.setLocation(x,y);
actor.setPoint(middlePoint);
/*if (imageCounter<=10) actor.setStatus("jump1");
else if (imageCounter<=40) actor.setStatus("jump2");
else if (imageCounter<=50) actor.setStatus("jump3");*/
repaint();
try {animator.sleep(1);} catch (InterruptedException e) {}
}

//actor.setStatus("idle");

}



I use the above on several occasions:

[1] When an enemy moves. Summary:

if (playerIsToVillainsRight) xToAdd = 50;
else if (playerIsToVillainsLeft) xToAdd = -50;
else if (playerIsOnSameRowAsVillain) xToAdd = 0;

if (playerIsBelowVillain) yToAdd = 50;
else if (playerIsAboveVillain) yToAdd = -50;
else if (playerIsOnSameColumnAsVillain) yToAdd = 0;

Point futurePoint = new Point (villainX+xToAdd, villainY+yToAdd);

moveActor(actors[currentVillain], futurePoint);



[2] When the player moves. Summary (this is inside the mouseClicked
listener):

//mouseLocation = MouseWEvent.getPoint();
//stl, str, etc = rectangles that represents future location of the
player on the board.

if (waitingForPlayer) {
if (stl.contains(mouseLocation) && !hoveringVillain(stl)) {
moveActor(actors[0], stl.getLocation());
waitingForPlayer = false;
}
if (str.contains(mouseLocation) && !hoveringVillain(str)) {
moveActor(actors[0], str.getLocation());
waitingForPlayer = false;
}
if (sbl.contains(mouseLocation) && !hoveringVillain(sbl)) {
moveActor(actors[0], sbl.getLocation());
waitingForPlayer = false;
}
if (sbr.contains(mouseLocation) && !hoveringVillain(sbr)) {
moveActor(actors[0], sbr.getLocation());
waitingForPlayer = false;
}
}




SO ... WHAT IS THE QUESTION?!?

What I see when I run the game:
the animation of the enemy (first code) works, but the animation of the
player (second code, inside the mouse listeners) -- doesn't!

The purpose of the moveActor is to move the enemy or player pixel by
pixel, until its in the future point,
instead of skipping the pixels between the squares and going straight
for the future location.

So what comes out is, that the enemy is moving pixel by pixel, and the
player simply jumps there!

I doublechecked and if I use moveActor with the player OUTSIDE the
mouse listener, it works (i think).

Any ideas what is the source of this problem?

Hope I made myself clear enough :D

Thanks,
Eshed.
 
J

jonck

Don't have the time right now to delve into your problem, but just one
quick tip, for JPanel (and all other Swing components) you should be
using paintComponent(), not paint().

Kind regards, Jonck
 
E

eshedz

Saying "paint()" was accidential.. I meant repaint().
The JPanel has PUBLIC VOID PAINT(GRAPHICS G), so to call that again I'm
using repaint()...

I think I'm confused... are you talking about replacing "paint(graphcis
g)" with "paintComponent(graphics g)" ?
 
B

Brendan Guild

(e-mail address removed) wrote in
I think I'm confused... are you talking about replacing
"paint(graphcis g)" with "paintComponent(graphics g)" ?

If you are overriding paint(Graphics) in Swing then you are asking for
trouble. I'm not sure exactly what the trouble will be, but the
documentation says you should just override paintComponent(Graphics).

This should help explain everything:

http://java.sun.com/docs/books/tutorial/uiswing/14painting/
 
B

Brendan Guild

(e-mail address removed) wrote in
I've created a little game and at some point I needed to make images
"move" on the JPanel (through paint()), on a checkers-based game
board. [snip]
The game works like so:
it has a mouse listener for clicks and movement, and the main game
process is THINK(), REPAINT(), which is repeated until the user wins
(the above is inside a while).
The mouse actions were added to the constructor so they are always
active, THINK changes the enemy's locations, and REPAINT simply calls
"paint()" again. [snip]
While doing that, I wanted to make the movement more sleek and clean,
instead of them simply jumping from one square to the other with a
blink of the eye.

So, I've created MOVEACTOR, that "moves" an enemy or a player from
its current point (actor.getPoint()) to the requested future square
(futurePoint). [snip]
What I see when I run the game:
the animation of the enemy (first code) works, but the animation of
the player (second code, inside the mouse listeners) -- doesn't!

The purpose of the moveActor is to move the enemy or player pixel by
pixel, until its in the future point,
instead of skipping the pixels between the squares and going straight
for the future location.

So what comes out is, that the enemy is moving pixel by pixel, and
the player simply jumps there!

I doublechecked and if I use moveActor with the player OUTSIDE the
mouse listener, it works (i think).

The problem is probably that your mouse listener is on the same thread
as your painting. You need to be very careful about how much you do in
the thread you are given to respond to events, such as mouse clicks.

In this case, you are calling repaint() from your listener. Repaint()
doesn't call your painting code directly, it puts a repaint event into
an event queue and then when the event queue gets a chance to run that
repaint will happen. Your painting will never happen until your
listener gives up control of that thread, so the end result is all you
see.

You need to run moveActor() from another thread. It should have occured
to you to wonder what would happen if the player clicked somewhere
while already in motion, right? Well, by moving the actor in another
thread, you'll be able to get more mouse click events during the motion
and you'll be able to decide what to do about them.

I'd suggest just sending your main thread into a loop with a small
sleep. You are going to have to use synchronization, just be sure to
synchronize inside your loop instead of synchronizing the entire loop.
Otherwise you'll lock your event thread and your game will freeze.
Don't blame me for that!

Here are some references:
http://java.sun.com/docs/books/tutorial/essential/threads/
http://mindprod.com/jgloss/swingthreads.html
http://mindprod.com/jgloss/thread.html
http://www.javaworld.com/javaworld/jw-10-1998/jw-10-toolbox.html
http://java.sun.com/j2se/1.3/docs/api/java/lang/Thread.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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top