Question: Write a program that draws a clock face with a time that the user enters in two text fields (one for the hours, one for the minutes).

I have Followed my example code, and come up with 3 classes. Clock, which sets the outines for drawing clock objects, ClockViewerFrame which sets up the JPanel with textfields and a draw button. and ClockViewer to run the whole thing. The problem I have is adding my clock to the panel and using the values calculated by taking user input from the text fields to set the hands of the clock in the right position.

My code thus far:

``````import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;

public class Clock
{
public Clock(double minuteAngle, double hourAngle, double hourRadius, double minuteRadius)
{
mAngle = minuteAngle;
hAngle = hourAngle;
hRadius = hourRadius;
mRadius = minuteRadius;
}

public void draw(Graphics2D g2)
{
Ellipse2D.Double face
= new Ellipse2D.Double(100, 100, 200, 200);
Point2D.Double centre
= new Point2D.Double(200, 200);
Point2D.Double hourOuter
= new Point2D.Double(150 + hRadius, 150 + hAngle);
Point2D.Double minuteOuter
= new Point2D.Double(200 + mRadius, 200 + mAngle);
Line2D.Double hourHand
= new Line2D.Double(centre, hourOuter);
Line2D.Double minuteHand
= new Line2D.Double(centre, minuteOuter);
g2.draw(face);
g2.draw(hourHand);
g2.draw(minuteHand);

}
private double hAngle;
private double mAngle;
private double hRadius;
private double mRadius;
}``````
``````import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Graphics;
import java.awt.Graphics2D;

public class ClockViewerFrame extends JFrame
{
public ClockViewerFrame()
{

createTextField();
createButton();
createPanel();

setSize(FRAME_WIDTH, FRAME_HEIGHT);
}

private void createTextField()
{
hourLabel = new JLabel("Hour: ");

final int FIELD_WIDTH = 10;
hourField = new JTextField(FIELD_WIDTH);
hourField.setText("");
minuteLabel = new JLabel("Hour: ");

minuteLabel = new JLabel("Minute: ");
minuteField = new JTextField(FIELD_WIDTH);
minuteField.setText("");
}

private void createButton()
{
button = new JButton("Draw");

class AddInterestListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int hour = (int) Double.parseDouble(
hourField.getText());
int minute = (int) Double.parseDouble(
minuteField.getText());
minuteX = 100 * Math.cos(6 * minute);
minuteY = 100 * Math.sin(6 * minute);
double  hourMinute = hour * 60;
hourX = 100 * Math.cos(0.5 * hourMinute);
hourY = 100 * Math.sin(0.5 * hourMinute);

}
}

ActionListener listener = new AddInterestListener();
button.addActionListener(listener);

}

private void createPanel()
{
panel = new JPanel();
panel.add(hourLabel);
panel.add(hourField);

panel.add(minuteLabel);
panel.add(minuteField);
panel.add(button);

add(panel);
}

private JLabel hourLabel;
private JLabel minuteLabel;
private JTextField hourField;
private JTextField minuteField;
private JButton button;

private JPanel panel;

public static double minuteX;
public static double hourX;
public static double hourY;
public static double minuteY;
private static final int FRAME_WIDTH = 450;
private static final int FRAME_HEIGHT = 100;

}``````
``````import javax.swing.JFrame;

public class ClockViewer
{
public static void main(String[] args)
{
JFrame frame = new ClockViewerFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}``````

many thanks in advance.

Well, first I think you need to decide where you want to draw the clock face. I assume you want to draw it on the ClockViewerFrame, in which case you are going to have to make it bigger to accomodate the clock face. Right now it has a width of 450 and a height of 100. It's going to have a bigger height. Have a data member of type Clock called clock in class ClockViewerFrame and instantiate it with the correct values when the user enters the hour and minute.

Next, create a paintComponent function for class ClockViewerFrame. Call that paintComponent function from actionPerformed after you calculate the proper angles and instantiate clock with them. Inside paintComponent, pass your Graphics2D object to your Clock.draw function, which will draw the clock face and the hands.

I think I have a problem with actually drawing the clock somewhere. I don't believe it's actually added to my panel, so its not displayed. Here is the updated code for the ClockViewerFrame class.

``````import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Graphics;
import java.awt.Graphics2D;

public class ClockViewerFrame extends JFrame
{
public ClockViewerFrame()
{

clock = new Clock(0, 0, 0, 0);
createTextField();
createButton();
createPanel();

setSize(FRAME_WIDTH, FRAME_HEIGHT);
}

private void createTextField()
{
hourLabel = new JLabel("Hour: ");

final int FIELD_WIDTH = 10;
hourField = new JTextField(FIELD_WIDTH);
hourField.setText("");
minuteLabel = new JLabel("Hour: ");

minuteLabel = new JLabel("Minute: ");
minuteField = new JTextField(FIELD_WIDTH);
minuteField.setText("");
}

private void createButton()
{
button = new JButton("Draw");

class AddInterestListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int hour = (int) Double.parseDouble(
hourField.getText());
int minute = (int) Double.parseDouble(
minuteField.getText());
minuteX = 100 * Math.cos(6 * minute);
minuteY = 100 * Math.sin(6 * minute);
double  hourMinute = hour * 60;
hourX = 100 * Math.cos(0.5 * hourMinute);
hourY = 100 * Math.sin(0.5 * hourMinute);
repaint();

}

}

ActionListener listener = new AddInterestListener();
button.addActionListener(listener);

}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
clock = new Clock(minuteY, hourY, hourX, minuteX);
clock.draw(g2);
}
private void createPanel()
{
panel = new JPanel();
panel.add(hourLabel);
panel.add(hourField);
panel.add(minuteLabel);
panel.add(minuteField);
panel.add(button);
add(panel);

}
private Clock clock;

private JLabel hourLabel;
private JLabel minuteLabel;
private JTextField hourField;
private JTextField minuteField;
private JButton button;

private JLabel resultLabel;
private JPanel panel;

public static double minuteX;
public static double hourX;
public static double hourY;
public static double minuteY;
private static final int FRAME_WIDTH = 450;
private static final int FRAME_HEIGHT = 600;

}``````

I don't think you want the AddInterestListener class where you have it (within function createButton). I don't see the purpose for the class. I'd get rid of it unless there is a good reason for it, and instead have your ClockViewerFrame class implement ActionListener and put that code in there. When you call repaint () from AddInterestListener currently, it is not calling the paintComponent function from your ClockViewerFrame class like you want, so the clock never gets drawn.

There is no paintComponent() method on JFrame, which is why it is not being called from repaint(). There is a paintComponents() method that paints all of the child components in the container by calling paintComponent() on each of them.

Because JFrame is a top-level container, you have to override paint() instead of paintComponent(). Be sure that you call super.paint(g) before your custom code so that everything else get's rendered properly. Your code will work with the following method

``````public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D)g;
clock = new Clock(minuteY, hourY, hourX, minuteX);
clock.draw(g2);
}``````
commented: Good post. +2

Thanks guys.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.