简体   繁体   中英

Moving sine curve in Swing/AWT GUI

I used doubly linked lists in order to create this moving sine curve (the code might be extremely primitive and disorganized but this is just a first draft and I barely know how to use 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);  
    }      
}  

However, the program doesn't run very smoothly. Are there any suggestions to make it run faster, and more smoothly?

ok there are some flaws that have to be corrected ^^

1) trigger your painting via threads

//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) don't make things complicated: just calculate f(x)=y during paint ^^
3) do only things in paint, that have to be done: don't set size everytime you paint

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

what's left? your setup ^^

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

you might want to take a look at buffering... if you don't like to do so, just use JPanel instead of Canvas (you'll have to overwrite paintComponent(Graphics g) instead of 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
        }
    }
}
public class DisplayGraphics extends Canvas{

Don't mix Swing and AWT. Swing components (anything that is a JComponent ) are double buffered by default. That helps avoid jerky rendering.

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

Whenever we override any paint method, we should immediately call the super method in order to erase the original drawing. But for Swing we would override paintComponent(Graphics) instead of paint(Graphics) .

Setting the foreground color should be done in the constructor once, then left alone. Calling it again triggers paint!

this.setSize(720,440);

And that is another thing that will trigger a repaint!

Further, it is better to override the size of getPreferredSize() method and pack() the top level window that contains it.. Whatever information, site, book you have been using, find a new & better version. This code shows bad practices in too many of the important parts..

Are there any suggestions to make it run faster, and more smooth?

Use a Swing component (eg JPanel ) instead of the Canvas . Make the changes & override the methods mentioned above. Create a Swing Timer that calls repaint() in the loop part.

See Performing Custom Painting & How to Use Swing Timers for better learning resources.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM