How to add real-time date and time into a JFrame component e.g. "status bar"?

date, java, swing

Solution

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.

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;
        }

    }

}

Problem

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.

Original source

Related problems