为了账号安全,请及时绑定邮箱和手机立即绑定

如何修复时钟闪烁?

如何修复时钟闪烁?

慕少森 2023-09-20 16:06:28
我目前正在使用 AWT Package 和 Swing 在 java 中制作模拟时钟。但数字时钟覆盖目前每隔一段时间就会闪烁一次,我想解决这个问题。我读过有关与 repaint() 结合实现双缓冲的内容,但我对如何实现它感到困惑。import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.Font;import java.awt.Graphics;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.GregorianCalendar;import java.util.TimeZone;import java.util.Timer;import java.util.TimerTask;import javax.swing.JFrame;public class Clock2d extends Applet {    GregorianCalendar cal;    Timer clockTimer = new Timer();    TimeZone clockTimeZone = TimeZone.getDefault();    public Clock2d() {        clockTimer.schedule(new TickTimerTask(), 0, 1000);    }    @Override    public void init() {    }    public void paint(Graphics g) {        g.setColor(Color.BLUE);        g.fillOval(40, 40, 220, 220);        g.setColor(Color.WHITE);        g.fillOval(50, 50, 200, 200);        double second = cal.get(Calendar.SECOND);        double minute = cal.get(Calendar.MINUTE);        double hours = cal.get(Calendar.HOUR);        for (int i = 0; i < 60; i++) {            int length = 90;            double rad = (i * 6) * (Math.PI) / 180;            if (i % 5 == 0) {                length = 82;                g.setColor(Color.BLUE);            } else {                g.setColor(Color.GRAY);            }            int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));            int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));            int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));            int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));            g.drawLine(x, y, x1, y1);        }除了编号数字时钟偶尔闪烁之外,代码完全按照预期工作。
查看完整描述

1 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

  1. public class Clock2d extends AppletAjava.awt.Applet不仅已被弃用,而且默认情况下也不是双缓冲的。更改它以扩展 a JPanel(即)。

  2. 然后改为public void paint(Graphics g) {尊重public void paintComponent(Graphics g) { super.paintComponent(g);油漆链。

  3. class TickTimerTask extends TimerTask使用 ajavax.swing.Timer代替。它在事件调度线程上运行,对 GUI 的任何调用都应在 EDT 上进行。

这是代码中表达的这三点。您在这个版本中看到“闪烁”的伪像吗?

import java.awt.*;

import java.awt.event.*;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.GregorianCalendar;

import java.util.TimeZone;

import javax.swing.*;


public class Clock2d extends JPanel {


    TimeZone clockTimeZone = TimeZone.getDefault();

    GregorianCalendar cal = 

            (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);

    ActionListener repaintListener = (ActionEvent e) -> {

        cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);

        repaint();

    };

    Timer clockTimer = new Timer(100, repaintListener);


    public Clock2d() {

        clockTimer.start();

    }


    @Override

    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        g.setColor(Color.BLUE);

        g.fillOval(40, 40, 220, 220);

        g.setColor(Color.WHITE);

        g.fillOval(50, 50, 200, 200);


        double second = cal.get(Calendar.SECOND);

        double minute = cal.get(Calendar.MINUTE);

        double hours = cal.get(Calendar.HOUR);


        for (int i = 0; i < 60; i++) {

            int length = 90;

            double rad = (i * 6) * (Math.PI) / 180;

            if (i % 5 == 0) {

                length = 82;

                g.setColor(Color.BLUE);

            } else {

                g.setColor(Color.GRAY);

            }

            int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));

            int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));

            int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));

            int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));

            g.drawLine(x, y, x1, y1);

        }


        drawHands(g, second, minute, hours);


        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");

        g.setColor(Color.BLUE);

        g.setFont(new Font("Tahoma", Font.BOLD, 16));

        g.drawString(sdf.format(cal.getTime()), 120, 20);

        g.setFont(new Font("Arial", Font.BOLD, 10));


    }


    public void drawHands(Graphics g, double second, double minute, double hours) {

        double rSecond = (second * 6) * (Math.PI) / 180;

        double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;

        double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;

        g.setColor(Color.RED);

        g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));

        g.setColor(Color.BLACK);

        g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));

        g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));

    }


    public static void main(String[] args) {

        // Swing / AWT GUIs should be created & changed on the EDT ..

        Runnable r = () -> {

            JFrame frame = new JFrame("Clock 2D");

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            frame.setPreferredSize(new Dimension(330, 330));

            Clock2d clock2d = new Clock2d();

            clock2d.setPreferredSize(new Dimension(320, 320));

            frame.setLayout(new BorderLayout());

            frame.getContentPane().add(clock2d, BorderLayout.CENTER);

            frame.pack();

            frame.setVisible(true);

        };

        // .. this is how we ensure that Runnable is on the EDT.

        SwingUtilities.invokeLater(r);

    }

}

关于字体的更多提示:


g.setFont(new Font("Arial", Font.BOLD, 10));

鉴于 Paint 方法被重复调用,最好在构造类时建立字体(两者)并将它们存储为类的属性(可以在方法中引用)。


但最好使用逻辑字体而不是“Arial”之类的字体,如下所示:


g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 10));

这不仅提供编译时检查,而且可以跨操作系统平台进行调整。例如,该SANS_SERIF字体在 Windows 上会生成 Arial,可能在大多数 *nix 盒子上,但在 OS X 上默认SANS_SERIF(未修饰的)字体是 Helvetica。


另一种字体 Tahoma 的问题更大。同样,它可能出现在许多 Windows 机器上,但最好要么对其进行测试并拥有备份列表,要么在时钟应用程序中提供字体。(假设您拥有发行权)。


查看完整回答
反对 回复 2023-09-20
  • 1 回答
  • 0 关注
  • 97 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信