Trigger event only after redrawing in Java Swing?

I am making a simple board game in java where I want to animate the dice roll. So I take pictures of cubes like this:

public Timer roll_dice = new Timer(50, this);
...
public void actionPerformed(ActionEvent evt) {
        if(roll_dice.getDelay() > 500){
            roll_dice.setDelay(50);
            roll_dice.stop();
            movePiece();
        }else{
            roll_dice.setDelay(roll_dice.getDelay() + 50);
            dice_panel.repaint(0);
        }
    }
}

movePiece(){
    //do some more painting
}

      

So, the cube goes in such a way as to show random numbers several times, and then slowly settle down by the number. After that, I would call the method movePiece()

. However, the redraw occurs sporadically, however, and spins everything up to be movePiece()

called before the die roll actually ends the animation.

Does anyone have any ideas how I can call movePiece only after the final repainting has occurred?

+3


source to share


3 answers


So, the cube goes in such a way as to show random numbers several times, and then slowly settle down by the number. After that, I would call the movePiece () method. However, the redrawing occurs sporadically, however, and twists everything so that movePiece () is called before the die roll has actually finished the animation.

What worries me is why your painting is happening sporadically - it just shouldn't be doing it, and maybe that's something you need to fix. I wonder if you are reading images from a file every time you draw a drawing or some other reason for slowing down drawing. If you need more help with this issue, then you will need to provide us with more information on how you make your painting. Regardless, you should avoid making your programming logic dependent on the painting, since you don't have complete control over when or even painting occurs.

Instead of redrawing images and calling redraw (), why not just put your cubed images in ImageIcons when you run your program, and then in your Swing timer, replace the icons in the JLabel? Then stop your timer when the delay is long enough, in which case, move the piece.



So, assuming you have multiple dice, each can be displayed by a JLabel, which is stored in a JLabel array called diceLabels, and ImageIcons can be stored in an array called diceIcons. Then you can do something like:

  public void actionPerformed(ActionEvent e) {
     if (roll_dice.getDelay() > 500) {
        roll_dice.setDelay(50);
        roll_dice.stop();
        movePiece(); // I like this -- this shouldn't change
     } else {
        roll_dice.setDelay(roll_dice.getDelay() + 50);
        // dice_panel.repaint(0);
        for (JLabel dieLabel : diceLabels) {
           int randomIndex = random.nextInt(diceIcons.length);
           dieLabel.setIcon(diceIcons[randomIndex]);
        }
     }
  }

      

I love your logic when you call movePiece()

and I think it should remain the same.

+1


source


You can call casting on another thread and connect () the current thread to the rolling one. So the main code will wait until the roll thread closes (pumping completed).

public void actionPerformed(ActionEvent evt) {
    if(roll_dice.getDelay() > 500){
        Thread rollerThread = new RollerThread();
        rollerThread.start();
        rollerThread.join();
        movePiece();
    }
    else{
        roll_dice.setDelay(roll_dice.getDelay() + 50);
        dice_panel.repaint(0);
    }
}

private RollerThread extends Thread
{
    public void run(){
        roll_dice.setDelay(50);
        roll_dice.stop();
    }
}

      



However, this may not work with EDT because renames must be scheduled in the queue. Perhaps you can split the event with SwingUtilities.invokeAndWait()

:

public void actionPerformed(ActionEvent evt) {
    Thread thread = new Thread(){
        public void run(){
            if(roll_dice.getDelay() > 500){
                SwingUtilities.invokeAndWait(new Runnable(){
                     public void run(){
                         roll_dice.setDelay(50);
                         roll_dice.stop();
                     }
                });
                movePiece();
            }
            else{
                 roll_dice.setDelay(roll_dice.getDelay() + 50);
                 dice_panel.repaint(0);
            }
        }
    };
    thread.start();
}

      

0


source


Does anything change if you put this call in movePiece();

in SwingUtilities.invokeLater(Runnable);

?

if(roll_dice.getDelay() > 500){
    roll_dice.setDelay(50);
    roll_dice.stop();

    SwingUtilities.invokeLater(new Runnable() {
        public void run() { movePiece(); }
    });
}
...

      

0


source







All Articles