2

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.

2 Answers2

5

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();
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • @Darth: See also the scaling approach taken in [`JDigit`](http://stackoverflow.com/a/4151403/230513). – trashgod Mar 11 '13 at 08:32
  • I apologize, I don't think I made the issue clear enough in my original question. I have edited it and added a few more lines at the end for clarification. –  Mar 11 '13 at 16:03
  • Awesome, I got that to split the number into digits, but now a new problem: Say the hour is 5, it gets put into the array as a 5 by itself when I need it to go into the array as two digits so that the array is {0, 5}. How do I do that? –  Mar 11 '13 at 22:13
  • Oh, how many ways you could do that. See the pad method in the example? `String min = pad(Calendar.getInstance().get(Calendar.MINUTE));` – MadProgrammer Mar 11 '13 at 22:34
3

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);
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I apologize, I don't think I made the issue clear enough in my original question. I have edited it and added a few more lines at the end for clarification. Will what you gave me still help me? –  Mar 11 '13 at 16:01
  • Yes, to the extent that I can guess the methods of `DigitPanel`. Use `s.substring()` to access the parts of the formatted date string. – trashgod Mar 11 '13 at 20:19