Я пытаюсь переместить мяч в апплете с помощью потока, но он не движется

Я пытаюсь переместить мяч в апплете с помощью потока, но он не движется. Может ли кто-нибудь помочь мне, поскольку я новичок в апплете и приступает к разработке игр... для справки, вот мой код

public class ballGame extends JApplet implements Runnable
{
    int x_pos=50;
    int y_pos=100;
    int rad=10;
    Thread t;

    public void start() 
    {
        super.start();
        t=new Thread("t");
        t.start();
    }

    public void paint(Graphics g) 
    {
        super.paint(g);
        g.setColor(Color.red);
        setBackground(Color.BLACK);
        g.drawOval(x_pos,y_pos,2*rad,2*rad); 

        while(true)
        {
            x_pos++;

            //validate();
            repaint();

            try
            {
                Thread.sleep(100);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

        }//end of while
    }//end of paint()
}

person anup navare    schedule 22.01.2013    source источник
comment
Этот ответ может стать хорошим шагом в изучении данного направления.   -  person nIcE cOw    schedule 22.01.2013


Ответы (6)


Swing — это однопоточная среда. То есть все обновления и взаимодействия выполняются в рамках одного потока. Swing также НЕ является потокобезопасным. Это означает, что все обновления пользовательского интерфейса ДОЛЖНЫ выполняться в контексте этого потока (потока диспетчеризации событий или ETD).

Любой код, который блокирует EDT, не позволит ему (среди прочего) перерисовывать пользовательский интерфейс и реагировать на ввод пользователя.

Ваш код рисования НИКОГДА не будет обновлять экран, на самом деле это заставит ваше приложение «зависнуть», так как метод paint не может завершиться и блокирует ETD.

Исключением является то, что метод paint быстро возвращается после вызова и может быть вызван повторно в быстрой последовательности.

Вообще говоря, Thread, вероятно, слишком много, что-то вроде javax.swing.Timer было бы более чем подходящим в этих обстоятельствах.

введите здесь описание изображения

public class AnimatedBoat {

    public static void main(String[] args) {
        new AnimatedBoat();
    }

    public AnimatedBoat() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new AnimationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class AnimationPane extends JPanel {

        private BufferedImage boat;
        private int xPos = 0;
        private int direction = 1;

        public AnimationPane() {
            try {
                boat = ImageIO.read(new File("boat.png"));
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        xPos += direction;
                        if (xPos + boat.getWidth() > getWidth()) {
                            xPos = getWidth() - boat.getWidth();
                            direction *= -1;
                        } else if (xPos < 0) {
                            xPos = 0;
                            direction *= -1;
                        }
                        repaint();
                    }

                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int y = getHeight() - boat.getHeight();
            g.drawImage(boat, xPos, y, this);

        }

    }

}

В качестве примечания. Вам редко придется переопределять метод paint контейнера верхнего уровня, такого как JApplet или JFrame, хотя для этого есть ряд веских причин, одна из которых вас больше всего интересует, это тот факт, что они не двойные буферизуется, что означает, что вы, вероятно, увидите мерцание при обновлении экрана.

Вместо этого лучше использовать что-то вроде JPanel и переопределить его метод paintComponent.

Взгляни на

Чтобы получить больше информации

nb Хотя я использовал JFrame для своего примера, было бы просто взять панель анимации и поместить ее в JApplet, это еще одна причина, по которой вам не нужно/не хочется расширяться из контейнеров верхнего уровня;)

person MadProgrammer    schedule 22.01.2013

Наличие бесконечного цикла в paint означает, что ни один проход метода не может быть завершен.

Также вы никогда не должны вызывать Thread.sleep(100) в методе paint. Это блокирует EDT и снижает производительность.

Вместо этого используйте Swing Timer для обновления и перерисовки. Также я бы подклассировал JComponent и переопределил paintComponent.

person Reimeus    schedule 22.01.2013
comment
Хорошо, Реймеус... я попробую использовать таймер свинга. Спасибо. - person anup navare; 22.01.2013

Вы не можете вызывать метод repaint() внутри paint(). И вы не можете организовать бесконечный цикл внутри метода paint() - тем самым вы блокируете рисование в своем апплете.

person Andremoniy    schedule 22.01.2013
comment
(придирчивый - Вы можете вызвать repaint из paint, ничто вас не остановит, но вы не должны ;)) +1 - person MadProgrammer; 22.01.2013
comment
@MadProgrammer Действительно, я имел в виду именно то, что вы shouldn't. Это очевидно :) - person Andremoniy; 22.01.2013

x_posявляется значением int, поэтому оно передается методам по значению, а не по ссылке. Вот почему, когда вы меняете его значение, значение внутри вашего круга не обновляется...

person pushy    schedule 22.01.2013

Вы создаете поток без метода run(). Этот метод должен содержать исполняемый код... Кроме того, метод paint() предназначен для рисования, а не обновления!

Поэтому переместите цикл while из метода paint() в метод run() вашего потока:

t=new Thread("t") {
    @Override
    public void run()
    {
        while(true)
        {
            x_pos++;

            //validate();
            repaint();

            try
            {
                Thread.sleep(100);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }//end of while
    }
};

Обратите внимание, что ballGame не требует части implement Runnable. Поскольку поток, который вы создали, предоставит его.

person Veger    schedule 22.01.2013
comment
На самом деле я написал run() и писал цикл while только в этом, но он не работал... Тем не менее я попробую еще раз.. спасибо за помощь - person anup navare; 22.01.2013
comment
Я полагаю, вы написали метод run() непосредственно в классе ballGame... Вы должны поместить его в класс Thread, чтобы добавить функциональности классу Thread, иначе он ничего не сделает! - person Veger; 22.01.2013
comment
И требуется реализация runnable, я думаю, иначе run() покажет ошибку - person anup navare; 22.01.2013
comment
Как я уже сказал, вы должны удалить часть implements Runnable из определения вашего класса. - person Veger; 22.01.2013
comment
Помещение run() в поток означает, где именно вы можете просто сказать мне, пожалуйста - person anup navare; 22.01.2013
comment
Мой ответ показывает, как это сделать: просто замените t=new Thread("t"); предоставленным кодом. - person Veger; 22.01.2013
comment
но t=new Thread(t) находится в методе запуска, я должен написать в нем run(), как вы написали в коде - person anup navare; 22.01.2013
comment
Хорошо! Вам действительно нужно прочитать JApplet и Thread, чтобы вы знали, для чего используются эти методы! - person Veger; 22.01.2013
comment
но почему тот же код, написанный внутри run(), не работал, можете ли вы сказать - person anup navare; 22.01.2013
comment
Потому что JApplet не интересует метод run(). Это точно так же, как и любой другой пользовательский метод, который вы можете добавить в файл ballClass. - person Veger; 22.01.2013

Имейте цикл while внутри метода run Runnable.

ОБНОВЛЕНИЕ:

Имейте это в методе запуска.

t=new Thread(this);
t.start();
person shazin    schedule 22.01.2013
comment
Я попытался поместить его в run(), но мяч все равно не двигался. - person anup navare; 22.01.2013