【问题标题】:Why does the clock flicker?为什么时钟会闪烁?
【发布时间】:2013-05-26 00:12:51
【问题描述】:

下面的代码是一个时钟的动画。

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

为什么必须在 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);
    }
}

【问题讨论】:

  • 在相同的尺寸上画两次,它不会填充
  • 抱歉,相同尺寸的两次是什么意思?

标签: java awt flicker double-buffering


【解决方案1】:

信不信由你,通过添加功能解决了问题:

    public void update(Graphics g)

       {

            paint(g);

       }

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

【讨论】:

  • 默认更新会清屏然后调用paint。这是在awt books 101中。这些年来忘记了。所以它打败了双重缓冲。当您执行此操作时,当前屏幕内容将保留,直到您在屏幕外缓冲区中准备新屏幕并将其绘制在一个绘图图像中
【解决方案2】:

这使用的是旧的 awt,它会在主框架上进行绘制 - 这不是制作摇摆 UI 的最佳方式。你可以试试这个:

  1. 让定时器 - 睡眠量减少或增加,尝试 300 或 800
  2. 使用面板进行绘图,将面板添加到框架中
  3. 使用 swing(使用 JComponent,它会自动双倍缓冲,以及一个 JFrame

对于 2 和 3,您可以保留原始类来制作 Frame/JFrame,并为添加到前者的 java.awt.Panel 或 javax.swing.JComponent 一个新类。

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

Thread.sleep(800);

【讨论】:

  • 感谢您的回答,我决心在awt中更好地理解它的机制。更改计时器 - 睡眠不起作用。如果它在您的系统上没有闪烁,请尝试放大窗口、移动等,它可能会。
猜你喜欢
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 2022-12-10
  • 1970-01-01
  • 2014-03-27
  • 2012-05-06
  • 2014-07-25
  • 1970-01-01
相关资源
最近更新 更多