Pergunta

The following code is an animation of a clock.

What changes would have to be made in the program to make it not flicker?

Why does the field initiation have to take place in the addNotify() function for the hands to be displayed?

You can copy all of it into one .java file and it should work (flicker ;) ).

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class ac extends Frame implements Runnable {

    // for double buffering
    Graphics og;
    Image oi;
    Thread t = null;
    int width, height;
    int timeH, timeM, timeS, radius = 50, lenH, lenM, lenS,
        lenIn, cx, cy, x1, y1, x2, y2;
    private boolean timeToQuit;

    ac() {

        addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent we) {
                stopRunning();
                dispose();
            }

        });

        setMinimumSize(new Dimension(300, 300));

        EventQueue.invokeLater(new Runnable() {

            public void run() {
                setVisible(true);
            }
        });
    }

    public void addNotify() {
        super.addNotify();

        width = getBounds().width;
        height = getBounds().height;
        setSize(width, height);

        lenH = 5 * radius / 10;
        lenM = 6 * radius / 10;
        lenS = 7 * radius / 10;
        lenIn = 8 * radius / 10;
        cx = width / 2;
        cy = height / 2;

        // for double buffering
        oi = createImage(width, height);

        og = oi.getGraphics();

    }

    public static void main(String [] args) {
        ac clock = new ac();
        clock.start();
    }

    public void start() {
        if (t == null) {
            t = new Thread(this);
            t.start();
        }
    }

    public void stopRunning() {
        timeToQuit = true;
    }

    public void run() {

        Thread.currentThread().setPriority(Thread.NORM_PRIORITY - 1);
        do {
            repaint();
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
            }
        }
        while (!timeToQuit);
        System.out.println("Quitting");

    }

    public void paint(Graphics g) {
        og.setColor(new Color(170, 170, 170));
        og.fillRect(0, 0, width, height);
        Calendar cal = new GregorianCalendar();
        timeH = cal.get(Calendar.HOUR);
        timeM = cal.get(Calendar.MINUTE);
        timeS = cal.get(Calendar.SECOND);

        if (timeH >= 12)
            timeH -= 12;

        for (int i = 1 ; i < 13 ; i++) {
            og.setColor(new Color(20, 20, 20));
            x2 = (int) (cx + radius * Math.sin(i * 2 * 3.14159f / 12));
            y2 = (int) (cy - radius * Math.cos(i * 2 * 3.14159f / 12));
            if (i % 3 != 0) {
                x1 = (int) (cx + 0.9f * radius * Math.sin(i * 2 * 3.14159f / 12));
                y1 = (int) (cy - 0.9f * radius * Math.cos(i * 2 * 3.14159f / 12));
            }
            else {
                x1 = (int) (cx + 0.8f * radius * Math.sin(i * 2 * 3.14159f / 12));
                y1 = (int) (cy - 0.8f * radius * Math.cos(i * 2 * 3.14159f / 12));
            }
            og.drawLine(x1, y1, x2, y2);
            og.setColor(new Color(230, 230, 230));
            og.drawLine(x1 - 1, y1 - 1, x2 - 1, y2 - 1);
        }

        og.setColor(new Color(20, 20, 20));
        x2 = (int) (cx + lenH * Math.sin((timeH + timeM / 60.0f + timeS / 3600.0f)
            * 2 * 3.14159f / 12));
        y2 = (int) (cy - lenH * Math.cos((timeH + timeM / 60.0f + timeS / 3600.0f)
            * 2 * 3.14159f / 12));
        og.drawLine(cx, cy, x2, y2);
        og.setColor(Color.red);
        og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);

        og.setColor(new Color(20, 20, 20));
        x2 = (int) (cx + lenM * Math.sin((timeM + timeS / 60.0f) * 2 * 3.14159f
            / 60));
        y2 = (int) (cy - lenM * Math.cos((timeM + timeS / 60.0f) * 2 * 3.14159f
            / 60));
        og.drawLine(cx, cy, x2, y2);
        og.setColor(Color.green);
        og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);

        og.setColor(new Color(20, 20, 20));
        x2 = (int) (cx + lenS * Math.sin(timeS * 2 * 3.14159f / 60));
        y2 = (int) (cy - lenS * Math.cos(timeS * 2 * 3.14159f / 60));
        og.drawLine(cx, cy, x2, y2);
        og.setColor(Color.blue);
        og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);

        og.setColor(new Color(20, 20, 20));
        og.drawOval((width - 2 * radius) / 2, (height - 2 * radius) / 2,
            2 * radius, 2 * radius);
        og.setColor(new Color(230, 230, 230));
        og.drawOval((width - 2 * radius) / 2 - 1, (height - 2 * radius) / 2 - 1,
            2 * radius, 2 * radius);

        g.drawImage(oi, 0, 0, this);
    }
}
Foi útil?

Solução 2

Believe it or not, the problem was solved by adding the function:

    public void update(Graphics g)

       {

            paint(g);

       }

But the question remains, why? And why aren't the hands displayed when you initiate the class fields outside the addNotify() function?

Outras dicas

This uses awt which is old and it paints on to the main Frame - not the best way to make a swing UI. You can try this :

  1. make the timer - sleep amount to less or more, try 300 or 800
  2. use a Panel to draw on, add the panel to the frame
  3. use swing (use a JComponent, it double buffers automatically, and a JFrame

For 2 and 3 you can keep original class to make Frame/JFrame and a new class for the java.awt.Panel or javax.swing.JComponent which is added to the former.

Does not flicker on my mac system, so i think its an OS + times its refreshed issue. Meaning suggestion 1 might work - try that first. Talking about line of code :

Thread.sleep(800);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top