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

Discussion in 'Java' started by eshedz@gmail.com, Oct 22, 2005.

  1. Guest

    [ 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.
     
    , Oct 22, 2005
    #1
    1. Advertising

  2. jonck Guest

    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
     
    jonck, Oct 22, 2005
    #2
    1. Advertising

  3. Guest

    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)" ?
     
    , Oct 23, 2005
    #3
  4. wrote in
    news::
    > 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/
     
    Brendan Guild, Oct 23, 2005
    #4
  5. wrote in
    news::

    > 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
     
    Brendan Guild, Oct 23, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andreas Beresko

    Add a JPanel to a JPanel...

    Andreas Beresko, Jul 14, 2004, in forum: Java
    Replies:
    6
    Views:
    27,079
  2. Rajesh.Rapaka

    paint my jpanel

    Rajesh.Rapaka, Apr 22, 2005, in forum: Java
    Replies:
    1
    Views:
    4,536
    Thomas Weidenfeller
    Apr 22, 2005
  3. Raphael Jolivet

    [JPanel] Drop Down JPanel

    Raphael Jolivet, Jul 18, 2008, in forum: Java
    Replies:
    1
    Views:
    1,578
    John B. Matthews
    Jul 18, 2008
  4. t1m1976
    Replies:
    1
    Views:
    2,472
    t1m1976
    Nov 7, 2010
  5. Matt Kruse
    Replies:
    2
    Views:
    180
Loading...

Share This Page