Java графический фон движется сам по себе - PullRequest
0 голосов
/ 10 февраля 2019

Я пытаюсь сделать очень простую анимацию, где слова из ArrayList перемещаются по экрану.Чтобы сделать это, я использовал метод drawString () и таймер, чтобы изменить позицию x каждый установленный объем мс.Мой метод paintComponent в настоящее время настроен так, чтобы рисовать два разных слова, сначала слово «Hello», а затем слово «World» через 2,5 секунды.

Моя проблема в том, что графическая система координат, кажется, движется, и, в результате, слова, которые я породил после первого «Hello», ведут себя по-разному.Слово «Мир» имеет постоянную х = 0, но оно появляется в середине экрана и также перемещается вместе со словом «Привет».Кроме того, сам розовый фон движется со скоростью, отличной от слов!

Больше всего меня огорчает то, что если я избавлюсь от строк 32-38 (код, который порождает слова),и только установить цвет фона, фон все еще движется.Однако, если я избавлюсь от строки 80 (метод, который меняет x), фон перестает двигаться.Это означает, что определенно существует связь между моим значением x и фоном, но я просто не могу понять, что это такое.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Word extends JPanel{
    private ArrayList<String> phrase;
    int x;
    private int y;
    private int interval;
    private Word(ArrayList<String> Phrase,int height,int Interval){
        interval = Interval;
        y = height;
        phrase = Phrase;
        this.setBackground(Color.WHITE);
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        this.setBackground(Color.MAGENTA);
        g.setColor(Color.BLACK);
        g.setFont(new Font("TimesRoman", Font.BOLD, 30));
        for (int num = 0; num < phrase.size(); num++){
            if(num == 2){
                g.drawString(phrase.get(num), 0, 100*(num+1));
            }else{
                g.drawString(phrase.get(num), x, 100*(num + 1));
            }
        }
    }

    public void changeX(){
        x += 1;
    }

    public ArrayList<String> getPhrase(){
        return phrase;
    }

    public int getX(){
        return x;
    }

    public int getY(){
        return y;
    }

    public int getInterval(){
        return interval;
    }
    public static void main(String[] args){
        final ArrayList<String> words = new ArrayList<String>();
        words.add("Hello");
//      words.add("World");
        final Word test = new Word(words, 100, 50);
        final JFrame frame = new JFrame("test");
        frame.setSize(800, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setBackground(Color.WHITE);
        frame.add(test);
        frame.setVisible(true);
        Timer testTimer = new Timer();
        TimerTask testTask = new TimerTask(){
            int counter = 0;
            boolean spawned = false;
            public void run(){
                test.changeX();
                frame.repaint();
                System.out.println(counter);
                if(counter>50 && !spawned){
                    words.add("World");
                    spawned = true;
                }
                counter++;
            }
        };
        testTimer.scheduleAtFixedRate(testTask, 0, test.getInterval());
    }
}

Я ожидал, что слово "Мир" появится в самой левой части кадра и останется на месте.

1 Ответ

0 голосов
/ 10 февраля 2019

Моя проблема в том, что графическая система координат, кажется, движется, и, в результате, слова, которые я породил после первого «Hello», ведут себя по-разному.Слово «Мир» имеет постоянную х = 0, но оно появляется в середине экрана и также перемещается вместе со словом «Привет».

Хорошо, немедленное количество проблем:

  1. Вы переопределяете getXgetY), который изменяет значения, используемые компонентом для определения его местоположенияна экране вот почему фон движется.
  2. Ваш for-loop никогда не достигнет 2, он всегда будет 0 или 1
  3. Вы никогда не должны менятьсясостояние компонента из любого метода рисования.Живопись должна только когда-либо рисовать текущее состояние.Это может вызвать дополнительные циклы рисования, которые могут потреблять все циклы ЦП

Swing также НЕ является поточно-ориентированным, что означает, что вы никогда не должны обновлять пользовательский интерфейс (или что-то, на что полагается пользовательский интерфейс) вне контекстапотока обработки событий (также, ArrayList)

См. Параллельность в Swing для получения дополнительной информации и Как использовать таймеры Swing для возможного решения.

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

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                WordPane wordPane = new WordPane();
                wordPane.add(new Entity("Hello", new Point(0, 100), new Point(1, 0)));
                final JFrame frame = new JFrame("test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().setBackground(Color.WHITE);
                frame.add(wordPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Timer timer = new Timer(50, new ActionListener() {
                    int counter = 0;
                    boolean spawned = false;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (counter > 50 && !spawned) {
                            wordPane.add(new Entity("World", new Point(0, 200), new Point(0, 0)));
                            spawned = true;
                        }
                        counter++;
                        wordPane.tick();
                        wordPane.repaint();
                    }
                });
                timer.start();;
            }
        });
    }

    public class Entity {

        private String text;
        private Point point;
        private Point delta;

        public Entity(String text, Point point, Point delta) {
            this.text = text;
            this.point = point;
            this.delta = delta;
        }

        public String getText() {
            return text;
        }

        public Point getPoint() {
            return point;
        }

        public void tick() {
            point.x += delta.x;
            point.y += delta.y;
        }

    }

    public class WordPane extends JPanel {

        private ArrayList<Entity> phrase = new ArrayList<>(25);
        private int interval;

        private WordPane() {
            this.setBackground(Color.MAGENTA);
            setFont(new Font("TimesRoman", Font.BOLD, 30));
        }

        public void tick() {
            for (Entity entity : phrase) {
                entity.tick();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 600);
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLACK);
            FontMetrics fm = g.getFontMetrics();
            for (Entity entity : phrase) {
                int x = entity.getPoint().x;
                int y = entity.getPoint().y + fm.getAscent();
                g.drawString(entity.text, x, y);
            }
        }

        public ArrayList<Entity> getPhrase() {
            return phrase;
        }

        public void add(Entity entity) {
            phrase.add(entity);
        }
    }
}
...