Question

I'm making a digital clock for a project and I have four classes: DigitalTimeUI, which is the JFrame class, TitlePanel, DigitPanel, and ColonPanel, which are JPanels for the item stated. When it is finished, it should look like this:

enter image description here

The part I am stuck on is adding the DigitPanels to the frame in the UI class. Here's what I have in the main class right now:

public class DigitalTimeUI extends JFrame {

public static GregorianCalendar currentDate;
final static int CLOCKWIDTH = 605;
final static int CLOCKHEIGHT = 200;

public static void main(String[] args) {
    int numOfDigits = 6;
    int startingX = 0;
    int startingY = 0;

    Font clockFont = new Font("Tahoma", Font.BOLD, 72);
    JFrame clock = new JFrame();

    clock.setSize(CLOCKWIDTH, CLOCKHEIGHT);
    clock.setVisible(true);
    clock.setResizable(false);
    clock.setDefaultCloseOperation(EXIT_ON_CLOSE);

    TitlePanel titlePanel = new TitlePanel();
    JLabel title = new JLabel("DIGITAL CLOCK");
    title.setFont(clockFont);
    title.setForeground(Color.BLACK);
    titlePanel.add(title);
    clock.add(titlePanel);

    DigitPanel digitPanel = new DigitPanel();
    JLabel digit;
    startingY = 115;
    while (numOfDigits > 0) {
        if ((numOfDigits % 2) == 0) {
            startingX += 5;
            digit = new JLabel(String.valueOf(0));

        }

    }
  }
}

The code is kind of a mess right now, I've still got some cleaning up to do after I get that last part figured out. That bottom part is just some scrap from my attempts to display the 6 digit fields. I think the main problem I'm having is finding a way to split up the time returned from GregorianCalendar and put them into 6 different boxes, then an efficient way to put them into the frame using a while loop or whatnot.

To clarify: The above picture was given to me by the instructor as a guideline to go by when formatting my clock. It also has 9 panels in it. The "DIGITAL TIME" is a panel of the TitlePanel class. The digit boxes are of the DigitPanel class and there are 6 of them. The colon boxes are of the ColonPanel class and there are two of them. The issue I am having is with splitting up the time into 6 different boxes. Like, where the picture shows "48", I need a way to take the value from GregorianCalendar.MINUTE or whatever and split it into a 4 and an 8 to put into each of those boxes. Thanks.

Was it helpful?

Solution

If I understand the question correctly...

You're working in a OO environment. You should break your design down to the smallest manageable units of work as you can.

For me, this means that each digit (or time unit) is the smallest unit of work. This would require a component that was simply capable of displaying a 0 padded int value.

From there, you could build it up a clock pane, using 3 digit panes as so on.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DigitalClock {

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

    public DigitalClock() {
        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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        private DigitPane hour;
        private DigitPane min;
        private DigitPane second;
        private JLabel[] seperator;

        private int tick = 0;

        public TestPane() {
            setLayout(new GridBagLayout());

            hour = new DigitPane();
            min = new DigitPane();
            second = new DigitPane();
            seperator = new JLabel[]{new JLabel(":"), new JLabel(":")};

            add(hour);
            add(seperator[0]);
            add(min);
            add(seperator[1]);
            add(second);

            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Calendar cal = Calendar.getInstance();
                    hour.setValue(cal.get(Calendar.HOUR_OF_DAY));
                    min.setValue(cal.get(Calendar.MINUTE));
                    second.setValue(cal.get(Calendar.SECOND));

                    if (tick % 2 == 1) {
                        seperator[0].setText(" ");
                        seperator[1].setText(" ");
                    } else {
                        seperator[0].setText(":");
                        seperator[1].setText(":");
                    }
                    tick++;
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

    }

    public class DigitPane extends JPanel {

        private int value;

        @Override
        public Dimension getPreferredSize() {
            FontMetrics fm = getFontMetrics(getFont());
            return new Dimension(fm.stringWidth("00"), fm.getHeight());
        }

        public void setValue(int aValue) {
            if (value != aValue) {
                int old = value;
                value = aValue;
                firePropertyChange("value", old, value);
                repaint();
            }
        }

        public int getValue() {
            return value;
        }

        protected String pad(int value) {
            StringBuilder sb = new StringBuilder(String.valueOf(value));
            while (sb.length() < 2) {
                sb.insert(0, "0");
            }
            return sb.toString();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); 
            String text = pad(getValue());
            FontMetrics fm = getFontMetrics(g.getFont());
            int x = (getWidth() - fm.stringWidth(text)) / 2;
            int y = ((getHeight()- fm.getHeight()) / 2) + fm.getAscent();
            g.drawString(text, x, y);
        }        
    }    
}

Updated

Basically you can do something like...

String min = String.valueOf(Calendar.getInstance().get(Calendar.MINUTE));
char[] digits = min.toCharArray();

OTHER TIPS

As shown here, use SimpleDateFormat to format your time. This will give you a formatted string that you can index to get the text for your components.

This related example uses the following formatter:

private static final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
private final Date now = new Date();
...
String s = df.format(now);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top