猿问

如何修复时钟闪烁?

我目前正在使用 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);

        }


除了编号数字时钟偶尔闪烁之外,代码完全按照预期工作。


慕少森
浏览 105回答 1
1回答

猛跑小猪

public class Clock2d extends AppletAjava.awt.Applet不仅已被弃用,而且默认情况下也不是双缓冲的。更改它以扩展 a&nbsp;JPanel(即)。然后改为public void paint(Graphics g) {尊重public void paintComponent(Graphics g) { super.paintComponent(g);油漆链。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 {&nbsp; &nbsp; TimeZone clockTimeZone = TimeZone.getDefault();&nbsp; &nbsp; GregorianCalendar cal =&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);&nbsp; &nbsp; ActionListener repaintListener = (ActionEvent e) -> {&nbsp; &nbsp; &nbsp; &nbsp; cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);&nbsp; &nbsp; &nbsp; &nbsp; repaint();&nbsp; &nbsp; };&nbsp; &nbsp; Timer clockTimer = new Timer(100, repaintListener);&nbsp; &nbsp; public Clock2d() {&nbsp; &nbsp; &nbsp; &nbsp; clockTimer.start();&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void paintComponent(Graphics g) {&nbsp; &nbsp; &nbsp; &nbsp; super.paintComponent(g);&nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.BLUE);&nbsp; &nbsp; &nbsp; &nbsp; g.fillOval(40, 40, 220, 220);&nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.WHITE);&nbsp; &nbsp; &nbsp; &nbsp; g.fillOval(50, 50, 200, 200);&nbsp; &nbsp; &nbsp; &nbsp; double second = cal.get(Calendar.SECOND);&nbsp; &nbsp; &nbsp; &nbsp; double minute = cal.get(Calendar.MINUTE);&nbsp; &nbsp; &nbsp; &nbsp; double hours = cal.get(Calendar.HOUR);&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < 60; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int length = 90;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double rad = (i * 6) * (Math.PI) / 180;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (i % 5 == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; length = 82;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.BLUE);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.GRAY);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g.drawLine(x, y, x1, y1);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; drawHands(g, second, minute, hours);&nbsp; &nbsp; &nbsp; &nbsp; SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");&nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.BLUE);&nbsp; &nbsp; &nbsp; &nbsp; g.setFont(new Font("Tahoma", Font.BOLD, 16));&nbsp; &nbsp; &nbsp; &nbsp; g.drawString(sdf.format(cal.getTime()), 120, 20);&nbsp; &nbsp; &nbsp; &nbsp; g.setFont(new Font("Arial", Font.BOLD, 10));&nbsp; &nbsp; }&nbsp; &nbsp; public void drawHands(Graphics g, double second, double minute, double hours) {&nbsp; &nbsp; &nbsp; &nbsp; double rSecond = (second * 6) * (Math.PI) / 180;&nbsp; &nbsp; &nbsp; &nbsp; double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;&nbsp; &nbsp; &nbsp; &nbsp; double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;&nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.RED);&nbsp; &nbsp; &nbsp; &nbsp; g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));&nbsp; &nbsp; &nbsp; &nbsp; g.setColor(Color.BLACK);&nbsp; &nbsp; &nbsp; &nbsp; g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));&nbsp; &nbsp; &nbsp; &nbsp; g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; // Swing / AWT GUIs should be created & changed on the EDT ..&nbsp; &nbsp; &nbsp; &nbsp; Runnable r = () -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JFrame frame = new JFrame("Clock 2D");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.setPreferredSize(new Dimension(330, 330));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Clock2d clock2d = new Clock2d();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clock2d.setPreferredSize(new Dimension(320, 320));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.setLayout(new BorderLayout());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.getContentPane().add(clock2d, BorderLayout.CENTER);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.pack();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; frame.setVisible(true);&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; // .. this is how we ensure that Runnable is on the EDT.&nbsp; &nbsp; &nbsp; &nbsp; SwingUtilities.invokeLater(r);&nbsp; &nbsp; }}关于字体的更多提示: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 机器上,但最好要么对其进行测试并拥有备份列表,要么在时钟应用程序中提供字体。(假设您拥有发行权)。
随时随地看视频慕课网APP

相关分类

Java
我要回答