为什么时钟会闪烁?

时间:2013-05-30 12:13:23

标签: java awt flicker double-buffering

以下代码是时钟的动画。

程序中必须进行哪些更改才能使其不闪烁?

为什么必须在addNotify()函数中进行字段启动才能显示指针?

您可以将所有文件复制到一个.java文件中,它应该可以工作(闪烁;))。

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

2 个答案:

答案 0 :(得分:1)

这使用了旧的awt并且它绘制在主框架上 - 而不是制作swing UI的最佳方式。你可以试试这个:

  1. 使计时器 - 睡眠量减少或更多,尝试300或800
  2. 使用面板绘制,将面板添加到框架
  3. 使用swing(使用JComponent,自动双缓冲,以及JFrame
  4. 对于2和3,您可以保留原始类来生成Frame / JFrame,并将java.awt.Panel或javax.swing.JComponent添加到前者中。

    不会在我的mac系统上闪烁,所以我认为它是一个OS +倍的刷新问题。意义建议1可能有用 - 首先尝试。谈论代码行:

    Thread.sleep(800);
    

答案 1 :(得分:1)

信不信由你,通过添加函数来解决问题:

    public void update(Graphics g)

       {

            paint(g);

       }

但问题仍然存在,为什么?当你在addNotify()函数之外启动类字段时,为什么不显示指针?