Использование JButton для запуска простой анимации

Я следую HeadFirst Java 2nd Edition и пытаюсь выполнить простую анимацию круга, движущегося по диагонали из одной точки в другую одним нажатием кнопки. Я использую JPanel для рисования круга и интерфейса ActionListener для получения события от кнопки. Когда я напрямую вызываю функцию анимации из 'main()', анимация работает нормально. Но когда я пытаюсь сделать это после нажатия кнопки, программа зависает и сразу отображает конечный результат.

Код:

import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;

    public class SimpleAnimation{
    int x=70;
    int y=70;
    JFrame frame;
    MyDrawPanel drawPanel;

    public static void main(String[] args) {
        SimpleAnimation gui=new SimpleAnimation();
        gui.initialize();
        // gui.animate();               //animation method
    }

    public void initialize(){
        frame=new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        drawPanel=new MyDrawPanel();
        frame.getContentPane().add(BorderLayout.CENTER,drawPanel);
        frame.setSize(400,400);
        frame.setVisible(true);
        JButton button=new JButton("Click me!");
        frame.getContentPane().add(BorderLayout.EAST,button);
        button.addActionListener(new OnclickListener());
    }

    public void animate(){
        for (int i=0;i<130 ;i++ ) {
            x++;
            y++;
            drawPanel.repaint();
            try{
                Thread.sleep(50);
                }catch(Exception e){}
            }
        }

        class MyDrawPanel extends JPanel{
            public void paintComponent(Graphics g){
                g.setColor(Color.white);
                g.fillRect(0,0,this.getWidth(), this.getHeight());
                g.setColor(Color.green);
                g.fillOval(x,y,40,40);
            }
        }

        class OnclickListener implements ActionListener{
            public  void actionPerformed(ActionEvent event){
                animate();
            }
        }
}

person Aneem    schedule 02.05.2015    source источник
comment
Вам следует ознакомиться с Timer документацией. Вы не должны спать в потоке пользовательского интерфейса (или выполнять любую другую логику, не связанную с пользовательским интерфейсом), поскольку это заблокирует перерисовку вашего графического интерфейса.   -  person Piotrek Bzdyl    schedule 02.05.2015
comment
См. Обнаружение/исправление висячей закрывающей скобки блока кода для проблемы, которую я больше не мог решить.   -  person Andrew Thompson    schedule 02.05.2015
comment
Не блокируйте EDT (поток отправки событий). Когда это произойдет, графический интерфейс «зависнет». См. раздел Параллелизм в Swing для получения подробной информации и исправления.   -  person Andrew Thompson    schedule 02.05.2015


Ответы (2)


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

Вам нужен таймер, а не вызов Thread.sleep(), чтобы установить расстояние между различными анимациями. В java.util есть таймер, но вместо него следует использовать таймер в Swing.

Я рекомендую поискать в Google «анимация на Java», где есть несколько сайтов, которые подробно объясняют вещи.

person arcy    schedule 02.05.2015
comment
Спасибо, посмотрю - person Aneem; 02.05.2015
comment
Спасибо, приятель!!, мне пришлось использовать таймер, чтобы исправить это!! - person Aneem; 02.05.2015
comment
а затем фактически всех казнят сразу, не слишком уверен в этом! Выполняется только одна перерисовка, независимо от того, сколько раз вы вызываете .repaint() в actionPerformed(). - person BaSsGaz; 30.09.2017

Я обнаружил, что у вас есть функция animate(), объявленная в классе SimpleAnimation, но вы вызываете функцию в классе OnclickListener. Это невозможно. Когда в классе OnclickListener в методе actionPerformed вы вызываете функцию animate(), это означает this.animate(). Таким образом, программа пытается найти функцию animate() в классе OnclickListener, который не может быть найден, что должно привести к ошибке компиляции.

Чтобы сделать то, что вы хотите, вы должны передать ссылку SimpleAnimation на класс OnclickListener в переменной, скажем, simpleAnimation, а затем вызвать simpleAnimation.animate(), и это должно работать.

person Blip    schedule 02.05.2015
comment
Код работает нормально. Я использую внутренние классы, поэтому код работает. - person Aneem; 02.05.2015