Перемещение синусоиды в графическом интерфейсе Swing/AWT

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

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

public class DisplayGraphics extends Canvas{  

    public void paint(Graphics g) {   

        setForeground(Color.RED);  
        this.setSize(720,440);

        class list {
            int pos;
            list next; 
            list prev;

            list(){
                int pos;
                list next ;
                list prev;
            }

            list(int pos){
                this.pos = pos;
            }

            list(int pos, list next){
                this.pos = pos;
                this.next = next;
            }


            public void setpos(int pos){
                this.pos= pos;
            }

            public void setnext(list next){
                this.next= next;
                next.prev=this;
            }

            public void display(list head){
                list tracker = head;
                int y;
                //displays the sincurve momentarily
                for (int i = 1;i<721; i++){
                    y = (int)(Math.sin(Math.toRadians(tracker.pos))*200)+200;
                    g.fillOval(i,y,3,3);
                    tracker = tracker.next;
                }  
            }
        }

        list temp = new list();
        temp.setpos(1);
        list head = temp;

        for (int i =2; i<720; i++){
            list thing = new list();
            thing.setpos(i);
            temp.setnext(thing);
            temp = thing;

        }
        list tail = new list(720);
        temp.setnext(tail);
        tail.setnext(head);

        //creates the moving display
        boolean run = true;
        while(run==true){
            head.display(head);

            //try {
                //Thread.sleep(10);

            //} catch(InterruptedException ex) {
               // Thread.currentThread().interrupt();
            //}
            g.clearRect(0, 0, getWidth(), getHeight());
            head = head.next ;  
       }
    }

    public static void main(String[] args) {  
        DisplayGraphics m=new DisplayGraphics(); 

        JFrame f=new JFrame();  
        f.add(m);  
        f.setSize(720,400);  
        //f.setLayout(null);  
        f.setVisible(true);  
    }      
}  

Тем не менее, программа работает не очень гладко. Есть ли предложения, чтобы он работал быстрее и плавнее?

2 ответа

public class DisplayGraphics extends Canvas{

Не смешивайте Swing и AWT. Компоненты Swing (все, что является JComponent) по умолчанию с двойной буферизацией. Это помогает избежать рваного рендеринга.

public void paint(Graphics g) { 
    setForeground(Color.RED);

Всякий раз, когда мы перезаписываем любой метод рисования, мы должны немедленно вызывать супер метод, чтобы стереть исходный рисунок. Но для свинга мы бы переопределили paintComponent(Graphics) вместо paint(Graphics),

Установка цвета переднего плана должна быть сделана в конструкторе один раз, затем оставлена ​​в покое. Повторный вызов вызывает краску!

this.setSize(720,440);

И это еще одна вещь, которая вызовет перекрас!

Далее лучше переопределить размер getPreferredSize() метод и pack() окно верхнего уровня, в котором оно содержится. Какую бы информацию, сайт, книгу вы использовали, найдите новую и лучшую версию. Этот код показывает плохие практики во многих важных частях.

Есть ли предложения, чтобы он работал быстрее и плавнее?

Используйте компонент Swing (например, JPanel) вместо Canvas, Внесите изменения и переопределите методы, упомянутые выше. Создать качели Timer что вызывает repaint() в части цикла.

См. Выполнение пользовательской рисования и Как использовать Swing Timers для улучшения учебных ресурсов.

Хорошо, есть некоторые недостатки, которые нужно исправить ^^

1) вызвать вашу картину через темы

//set isRunning=false to stop repaint
private boolean isRunning = true;
private void startUpdateThread(){
    Runnable r = new Runnable() {
        public void run() {

            while(isRunning){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //repaint calls the paint(Graphics g)-method
            repaint();
            }
        }
    };

    Thread t = new Thread(r);
    t.setDaemon(true);
    t.start();
}

2) не усложняйте ситуацию: просто вычислите f(x)=y во время рисования ^^
3) делать только то, что нужно, в краске: не устанавливайте размер каждый раз, когда рисуете

private int xCount = 0;
public void paint(Graphics g) {

    //setSize(...)

    xCount = xCount + 1;
    for (int dx = 1; dx < 721; dx++) {

        int x = (xCount%721)+dx;
        int y = (int) (Math.sin(Math.toRadians(x)) * 200) + 200;
        g.fillOval(dx, y, 3, 3);
    }
}

что осталось? ваши настройки ^^

public static void main(String[] args) {
    DisplayGraphic m = new DisplayGraphic();
    m.startUpdateThread();
    m.setSize(720, 440);

    JFrame f = new JFrame();
    f.add(m);
    f.setSize(720, 400);
    f.setVisible(true);
}

Возможно, вы захотите взглянуть на буферизацию... если вам не нравится это делать, просто используйте JPanel вместо холста (вам придется перезаписать paintComponent(Graphics g) вместо paint(Graphics g))

public class DisplayGraphic extends JPanel {

    private int xCount = 0;
    public void paintComponent(Graphics g) {        
        super.paintComponent(g);
        //...
        //same as paint in above
        }
    }
}
Другие вопросы по тегам