简体   繁体   English

仅在Java Swing中重绘后触发事件?

[英]Trigger event only after repaint in Java Swing?

I am making a simple board game in java, where I want to animate a dice roll. 我在java中制作一个简单的棋盘游戏,我想要制作一个骰子动画。 So I flash pictures of a dice 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 die is going so show random numbers for a few times, and then slowly settle on a number. 因此,模具将如此显示随机数几次,然后慢慢地确定一个数字。 After that is done I would like to call the movePiece() method. 完成之后我想调用movePiece()方法。 However, as it is, the the repaint occurs sporadically and screws everything up so that movePiece() gets called before the dice roll is actually finished animating. 然而,实际上,重新出现偶尔并将所有内容拧紧,以便在骰子卷实际完成动画之前调用movePiece()

Does anyone have any ideas how I can call movePiece only after the final repaint has happened? 有没有人有任何想法,我怎么能在最后的重绘发生后调用movePiece?

So the die is going so show random numbers for a few times, and then slowly settle on a number. 因此,模具将如此显示随机数几次,然后慢慢地确定一个数字。 After that is done I would like to call the movePiece() method. 完成之后我想调用movePiece()方法。 However, as it is, the the repaint occurs sporadically and screws everything up so that movePiece() gets called before the dice roll is actually finished animating. 然而,实际上,重新出现偶尔并将所有内容拧紧,以便在骰子卷实际完成动画之前调用movePiece()。

What worries me here is why your painting is occurring sporadically -- it simply shouldn't be doing that, and perhaps that is what you need to fix. 这里让我担心的是你的绘画偶尔发生的原因 - 它根本不应该这样做,也许就是你需要解决的问题。 I wonder if you're reading in the images from the file each time you do the drawing or some other cause for slowing the drawing down. 我想知道你每次进行绘图时是否正在读取文件中的图像,或者其他原因是为了减慢绘图速度。 If you need more help regarding this issue, then you'll have to give us more information on how you do your painting. 如果您在此问题上需要更多帮助,那么您必须向我们提供有关您如何进行绘画的更多信息。 Regardless, you should avoid having program logic be dependent on painting as you don't have full control over when or even if painting will occur. 无论如何,你应该避免使程序逻辑依赖于绘画,因为你无法完全控制何时或甚至是否会发生绘画。

Rather than redrawing images and calling repaint(), why not simply put your rolling dice images into ImageIcons on program start up, and then in your Swing Timer, swap icons in a JLabel? 为什么不在程序启动时简单地将滚动骰子图像放入ImageIcons,然后在Swing Timer中,在JLabel中交换图标,而不是重绘图像并调用repaint()。 Then stop your Timer when the delay gets long enough and in that if block, move your piece. 然后在延迟时间足够长的时候停止你的计时器,如果阻止,移动你的作品。

So, assuming that you have several dice, each can be displayed by a JLabel that is held in an array of JLabel called diceLabels, and the ImageIcons can be held in an array called diceIcons. 因此,假设您有几个骰子,每个骰子都可以由JLabel显示,该JLabel保存在名为diceLabels的JLabel数组中,ImageIcons可以保存在名为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 like your logic on when you call movePiece() and I think that this should remain unchanged. 当你调用movePiece()时我喜欢你的逻辑,我认为这应该保持不变。

You can call the rolling in another thread and join() the current thread to the rolling one. 您可以在另一个线程中调用滚动并将当前线程连接()到滚动线程。 That way the main code will wait until the roll thread dies (finished rolling). 这样主代码将等待滚动螺纹死亡(完成滚动)。

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 might not work with the EDT - because repaints should be scheduled to the queue. 但是,这可能不适用于EDT - 因为重绘应该安排到队列中。 Maybe you can shedule the event using the SwingUtilities.invokeAndWait() : 也许你可以使用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();
}

Does anything change if you put that call to movePiece(); 如果你把这个调用放到movePiece();什么变化吗movePiece(); in a SwingUtilities.invokeLater(Runnable); SwingUtilities.invokeLater(Runnable); ?

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM