4

Like the one we add into the corner of presentation slides.

I already have SwingX library added and working, in case that could help with something.

Dan D.
  • 32,246
  • 5
  • 63
  • 79
Rasshu
  • 1,764
  • 6
  • 22
  • 53

4 Answers4

8

Basically, you want to use a JLabel for displaying the date/time, a javax.swing.Timer set to a regular interval to update the label and a DateFormat instance to format the date value...

enter image description here

public class PlaySchoolClock {

    public static void main(String[] args) {
        new PlaySchoolClock();
    }

    public PlaySchoolClock() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ClockPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    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, 48f));
            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()));
        }
    }
}

This example uses a time interval of half a second. The main reason for this is I don't go to the trouble of trying to calculate how far we are away from the next second when we set up the initial delay. This ensures that we are always up-to-date

The next question is to ask "why?" This kind of setup is relatively expensive, with the timer firing every half second (to catch any edge cases) and updating the screen, when most OS's actually have a date/time already on the screen...IMHO

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
6

I created a JStatusBar from many nested JPanels. I was surprised at how many JPanels it took to create a status bar.

JPanels. JPanels everywhere.

Here's the test GUI.

enter image description here

And here's the JStatusBar class. The status bar has a leftmost status update area. On the right, you can add as many status areas as you want, with a separator bar. The only limit is the width of the status bar.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JPanel;

public class JStatusBar extends JPanel {

    private static final long serialVersionUID = 1L;

    protected JPanel leftPanel;
    protected JPanel rightPanel;

    public JStatusBar() {
        createPartControl();
    }

    protected void createPartControl() {    
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(getWidth(), 23));

        leftPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 3));
        leftPanel.setOpaque(false);
        add(leftPanel, BorderLayout.WEST);

        rightPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 5, 3));
        rightPanel.setOpaque(false);
        add(rightPanel, BorderLayout.EAST);
    }

    public void setLeftComponent(JComponent component) {
        leftPanel.add(component);
    }

    public void addRightComponent(JComponent component) {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 0));
        panel.add(new SeparatorPanel(Color.GRAY, Color.WHITE));
        panel.add(component);
        rightPanel.add(panel);
    }

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

        int y = 0;
        g.setColor(new Color(156, 154, 140));
        g.drawLine(0, y, getWidth(), y);
        y++;

        g.setColor(new Color(196, 194, 183));
        g.drawLine(0, y, getWidth(), y);
        y++;

        g.setColor(new Color(218, 215, 201));
        g.drawLine(0, y, getWidth(), y);
        y++;

        g.setColor(new Color(233, 231, 217));
        g.drawLine(0, y, getWidth(), y);

        y = getHeight() - 3;

        g.setColor(new Color(233, 232, 218));
        g.drawLine(0, y, getWidth(), y);
        y++;

        g.setColor(new Color(233, 231, 216));
        g.drawLine(0, y, getWidth(), y);
        y++;

        g.setColor(new Color(221, 221, 220));
        g.drawLine(0, y, getWidth(), y);
    }

}

The separator bar is yet another JPanel.

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

public class SeparatorPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    protected Color leftColor;
    protected Color rightColor;

    public SeparatorPanel(Color leftColor, Color rightColor) {
        this.leftColor = leftColor;
        this.rightColor = rightColor;
        setOpaque(false);
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.setColor(leftColor);
        g.drawLine(0, 0, 0, getHeight());
        g.setColor(rightColor);
        g.drawLine(1, 0, 1, getHeight());
    }

}

And finally, the simulator class that shows you how to use the JStatusBar.

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class StatusBarSimulator implements Runnable {

    protected TimerThread timerThread;

    @Override
    public void run() {
        JFrame frame = new JFrame();
        frame.setBounds(100, 200, 400, 200);
        frame.setTitle("Status Bar Simulator");

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new BorderLayout());

        JStatusBar statusBar = new JStatusBar();
        JLabel leftLabel = new JLabel("Your application is running.");
        statusBar.setLeftComponent(leftLabel);

        final JLabel dateLabel = new JLabel();
        dateLabel.setHorizontalAlignment(JLabel.CENTER);
        statusBar.addRightComponent(dateLabel);

        final JLabel timeLabel = new JLabel();
        timeLabel.setHorizontalAlignment(JLabel.CENTER);
        statusBar.addRightComponent(timeLabel);

        contentPane.add(statusBar, BorderLayout.SOUTH);

        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                exitProcedure();
            }
        });

        timerThread = new TimerThread(dateLabel, timeLabel);
        timerThread.start();

        frame.setVisible(true);
    }

    public void exitProcedure() {
        timerThread.setRunning(false);
        System.exit(0);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new StatusBarSimulator());
    }

    public class TimerThread extends Thread {

        protected boolean isRunning;

        protected JLabel dateLabel;
        protected JLabel timeLabel;

        protected SimpleDateFormat dateFormat = 
                new SimpleDateFormat("EEE, d MMM yyyy");
        protected SimpleDateFormat timeFormat =
                new SimpleDateFormat("h:mm a");

        public TimerThread(JLabel dateLabel, JLabel timeLabel) {
            this.dateLabel = dateLabel;
            this.timeLabel = timeLabel;
            this.isRunning = true;
        }

        @Override
        public void run() {
            while (isRunning) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        Calendar currentCalendar = Calendar.getInstance();
                        Date currentTime = currentCalendar.getTime();
                        dateLabel.setText(dateFormat.format(currentTime));
                        timeLabel.setText(timeFormat.format(currentTime));
                    }
                });

                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                }
            }
        }

        public void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }

    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • ehhh .... you _know_ it's wrong to access Swing components off the EDT, so why do you show an example spreading such wrongness :-) – kleopatra Nov 14 '12 at 14:30
  • Thank you kindly! I'll study this code next month (university exams this month). But I want to know two details: 1) Are time and date updated because of "Calendar currentTime (...) (currentTime.getTime()))"? 2) Does "Thread.sleep(5000L)" means it's updated every 5 seconds? – Rasshu Nov 14 '12 at 14:35
  • What would be a better approach regarding this EDT detail, kleopatra? – Rasshu Nov 14 '12 at 14:38
  • 1
    1) Yes. 2) Yes. Since I'm only displaying minutes, updating every 5 seconds is adequate. – Gilbert Le Blanc Nov 14 '12 at 14:38
  • 1
    @kleopatra: Fixed. Sometimes, I forget things. :-) – Gilbert Le Blanc Nov 14 '12 at 14:44
  • 1
    happens to all of us :-) BTW, no need for a custom statusbar, SwingX already has it (though not particularly nice looking, afair) – kleopatra Nov 14 '12 at 14:55
  • 1
    IMHO, A Timer would be a much better solution than a thread that spends most of its time sleeping. I also think that it's best to point the OP in the direction of the correct answer, including reference material, rather than writing the whole solution for them. The latter is more conducive to learning than the former. – GreyBeardedGeek Nov 14 '12 at 17:48
  • @GreyBeardedGeek: In most cases, I agree that pointing the OP in the right direction is preferred. However, a status bar is sufficiently difficult to produce that I felt providing the solution was correct. As kleopatra pointed out, a status bar is included in SwingX as a component. – Gilbert Le Blanc Nov 14 '12 at 19:41
  • I'll try to discover what each part means and does after exams this month. In case I encounter a problem, I come back here. :) Thanks, dudes. – Rasshu Nov 17 '12 at 23:04
3

Add a label component at the appropriate place in your JFrame's component hirerarchy (maybe a JToolBar?).

Then create a timer that fires once per second, and add an ActionListener to it that updates the text of the label with the current time.

See the accepted answer at Using SwingWorker and Timer to display time on a label?

Community
  • 1
  • 1
GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
2

Create a SimpleDateFormat object that will help you format the current date. Add a JLabel to your JFrame. In a separate thread, create a loop that keeps reading the current date, format it to a String and pass it to the JLabel in the EDT. Make the separate thread sleep for one second or less before updating the label again.

Dan D.
  • 32,246
  • 5
  • 63
  • 79