Триггерное событие только после перерисовки в Java Swing? - PullRequest
3 голосов
/ 21 марта 2012

Я делаю простую настольную игру в Java, где я хочу анимировать бросок костей. Поэтому я высвечиваю изображения кости, как это:

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
}

Итак, кубик собирается, так что покажите случайные числа несколько раз, а затем медленно остановитесь на числе. После этого я хотел бы вызвать метод movePiece(). Тем не менее, как это и есть, перекрашивание происходит спорадически и все портит, так что movePiece() вызывается до того, как бросок костей на самом деле закончится.

У кого-нибудь есть идеи, как я могу вызвать movePiece только после того, как произошла окончательная перекраска?

Ответы [ 3 ]

1 голос
/ 21 марта 2012

Итак, кубик собирается, так что покажите случайные числа несколько раз, а затем медленно выбирайте число.После этого я хотел бы вызвать метод movePiece ().Однако, так как это, перерисовка происходит спорадически и все перепутывает, так что movePiece () вызывается до того, как бросок игральных костей на самом деле заканчивает анимацию.

Что меня беспокоит, так это то, почему ваша картина происходитвремя от времени - просто не следует этого делать, и возможно , что - это то, что вам нужно исправить.Интересно, читаете ли вы изображения из файла каждый раз, когда выполняете рисование, или по какой-либо другой причине для замедления рисования.Если вам нужна дополнительная помощь по этому вопросу, вам нужно будет предоставить нам больше информации о том, как вы рисуете.В любом случае, вы должны избегать зависимости логики программы от рисования, поскольку у вас нет полного контроля над тем, когда или даже будет происходить рисование.

Вместо того, чтобы перерисовывать изображения и вызывать repaint (), почему бы просто не помещать изображения с вращающимися кубиками в ImageIcons при запуске программы, а затем в таймере Swing поменять значки в JLabel?Затем остановите ваш таймер, когда задержка станет достаточно большой, и в этом случае, если блок переместит вашу фигуру.

Итак, при условии, что у вас есть несколько кубиков, каждый может быть отображен с помощью JLabel, который содержится в массиве JLabel.называется diceLabels, и ImageIcons может храниться в массиве под названием diceIcons.Тогда вы можете сделать что-то вроде:

  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]);
        }
     }
  }

Мне нравится ваша логика, когда вы звоните movePiece(), и я думаю, что это должно остаться без изменений.

0 голосов
/ 21 марта 2012

Что-нибудь изменится, если вы поместите этот вызов на movePiece(); в SwingUtilities.invokeLater(Runnable);?

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

    SwingUtilities.invokeLater(new Runnable() {
        public void run() { movePiece(); }
    });
}
...
0 голосов
/ 21 марта 2012

Вы можете вызвать переход в другой поток и присоединить () текущий поток к переходу.Таким образом, основной код будет ждать до тех пор, пока поток прокрутки не прекратит работу (закончит работу).

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();
    }
}

Однако это может не сработать с EDT - поскольку перерисовки должны быть запланированы в очередь,Может быть, вы можете запланировать событие, используя 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...