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:
The part I am stuck on is adding the DigitPanel
s 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.
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();