Time doesn't repaint in Applet
Asked Answered
B

3

0

I have a small problem but I don't know to fix it. I create simple Applet in which should be simple digital clock. I created all methods correctly but repaint methods doesn't repaint my applet. Can you check my code and say where is mistake. Thanks.

public class DigitalClock extends JApplet implements Runnable {

private Thread timeThread;
Date date = new Date();

public void start() {
    timeThread = new Thread(this, "Clock");
    timeThread.start();
}

@Override
public void stop() {
    if (timeThread == null) {
        return;
    }
    timeThread = null;
}

@Override
public void run() {
    while (timeThread != null) {
        repaint();
        try {
            timeThread.sleep(1000);
        } catch (InterruptedException e) {
        }
    }
}

@Override
public void paint(Graphics g) {
    date.setTime(System.currentTimeMillis());
    g.drawString(date.toString(), 50, 95);
}
}
Balzer answered 7/2, 2014 at 3:35 Comment(1)
Why code an applet? If it is due to spec. by teacher, please refer them to Why CS teachers should stop teaching Java applets.Warmth
D
5

Just use a javax.swing.Timer. See how to use Swing Timer

Here's an example. But rather than painting on top-level container like JApplet which you are doing, I'm painting on JPanel which is more recommended

enter image description here

import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.*;

public class TimerPanel extends JPanel {

    private String dateString;
    private final SimpleDateFormat format;
    private final Font font;
    private final Date date;

    public TimerPanel() {
        format = new SimpleDateFormat("hh:mm:ss a");
        font = new Font("impact", Font.PLAIN, 30);
        date = new Date();

        date.setTime(System.currentTimeMillis());
        dateString = format.format(date);

        Timer timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                date.setTime(System.currentTimeMillis());
                dateString = format.format(date);
                repaint();
            }
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setFont(font);
        FontMetrics fm = g.getFontMetrics(font);
        int width = fm.stringWidth(dateString);
        int height = fm.getAscent();
        int x = getWidth() / 2 - width / 2;
        int y = getHeight() / 2 + height / 2;

        g.drawString(dateString, x, y);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(300, 100);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TimerPanel timer = new TimerPanel();
                JOptionPane.showMessageDialog(
                        null, timer, "Digital Clock", JOptionPane.PLAIN_MESSAGE);
            }
        });
    }
}

More directly answering your question, your code works when I test it, the only thing you're forgetting to do is call super.paint(). Works as expected after doing so

@Override
public void paint(Graphics g) {
    super.paint(g);

You'll want to avoid Thread.sleep though. You may notice this causes flickering. It's preferred to use javax.swing.Timer. That's why I answered with my example first.

Disseisin answered 7/2, 2014 at 4:16 Comment(0)
O
1

Look at this another example. As @peeskillet answer, I also used JPanel to show time, but in my code I am using JLabel to show time.

public class ClockPane extends JPanel {

    private JLabel clock;

    public ClockPane() {
        setLayout(new BorderLayout());
        clock = new JLabel();
        clock.setHorizontalAlignment(JLabel.CENTER);
        clock.setFont(UIManager.getFont("Label.font").deriveFont(Font.BOLD, 32f));
        tickTock();
        add(clock);

        Timer timer = new Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                tickTock();
            }
        });
        timer.setRepeats(true);
        timer.setCoalesce(true);
        timer.setInitialDelay(0);
        timer.start();
    }

    public void tickTock() {
        clock.setText(DateFormat.getDateTimeInstance().format(new Date()));
    }
    public static void main(String args[]){
        SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            ClockPane clock = new ClockPane();
            JOptionPane.showMessageDialog(
                    null, clock, "Digital Clock", JOptionPane.PLAIN_MESSAGE);
        }
    });
    }
}

clock

Onanism answered 7/2, 2014 at 4:38 Comment(0)
J
0

You should use a private attribute like

private boolean running = true;

You set it in stop-method to false. And in run-method you evaluate it as stop condition instead of evaluating timeThread != null. This procedure is safer because otherwise you get into concurrency problems within run-method caused by NullPointerException.

And you should check the applet state by watching its console output in browser plugin. Do you see exceptions?

Jostle answered 7/2, 2014 at 3:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.