Task

Draw a clock.



More specific:

 Draw a time keeping device. It can be a stopwatch, hourglass, sundial, a mouth counting "one thousand and one", anything. Only showing the seconds is required, e.g.: a watch with just a second hand will suffice. However, it must clearly change every second, and the change must cycle every so often (one minute, 30 seconds, etc.) It must be drawn; printing a string of numbers to your terminal doesn't qualify. Both text-based and graphical drawing are OK.
 The clock is unlikely to be used to control space flights, so it needs not be hyper-accurate, but it should be usable, meaning if one can read the seconds off the clock, it must agree with the system clock.
 A clock is rarely (never?) a major application: don't be a CPU hog and poll the system timer every microsecond, use a proper timer/signal/event from your system or language instead. For a bad example, many OpenGL programs update the frame-buffer in a busy loop even if no redraw is needed, which is very undesirable for this task.
 A clock is rarely (never?) a major application: try to keep your code simple and to the point. Don't write something too elaborate or convoluted, instead do whatever is natural, concise and clear in your language.


Key points
 animate simple object
 timed event 
 polling system resources 
 code clarity


/* NetRexx */
options replace format comments java crossref symbols binary
 
import javax.swing.Timer
 
-- .+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8
class RClockSwing public extends JFrame
  -- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  properties constant
    K_TITLE = String "Clock"
    isTrue = boolean (1 == 1)
    isFalse = \isTrue
  properties inheritable
    content = Container
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method RClockSwing() public
    this(K_TITLE)
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method RClockSwing(title = String) public
    super(title)
    initFrame()
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method initFrame() private
    content = getContentPane()
    content.setLayout(BorderLayout())
    content.add(RClockSwing.Panel(), BorderLayout.CENTER)
    setResizable(isFalse)
    pack()
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method main(args = String[]) public static
    clockFace = JFrame
    clockFace = RClockSwing()
    clockFace.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    clockFace.setVisible(isTrue)
    return
 
--..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8
class RClockSwing.Panel shared extends JPanel implements ActionListener
  properties constant
    degrees450 = double Math.PI * 2.5
    degrees006 = double Math.PI / 30.0
    degrees030 = double degrees006 * 5
    size = int 350
    spacing = int 10
    diameter = int size - 2 * spacing
    x1 = int diameter / 2 + spacing
    y1 = int diameter / 2 + spacing
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method Panel() public
    super()
    initPanel()
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method initPanel() public
    setPreferredSize(Dimension(size, size))
    setBackground(Color.WHITE)
    ptimer = Timer(1000, this)
    ptimer.start()
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method paintComponent(gr = Graphics) public
    super.paintComponent(gr)
    g2 = Graphics2D gr
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    gr.setColor(Color.black)
    gr.drawOval(spacing, spacing, diameter, diameter)
    cdate = Calendar.getInstance()
    hours   = cdate.get(Calendar.HOUR)
    minutes = cdate.get(Calendar.MINUTE)
    seconds = cdate.get(Calendar.SECOND)
    angle = double degrees450 - (degrees006 * seconds)
    drawHand(gr, angle, int (diameter / 2 - 10), Color.red)
    minsecs = double (minutes + seconds / 60.0)
    angle = degrees450 - (degrees006 * minsecs)
    drawHand(gr, angle, int (diameter / 3), Color.black)
    hourmins = double (hours + minsecs / 60.0)
    angle = degrees450 - (degrees030 * hourmins)
    drawHand(gr, angle, int (diameter / 4), Color.black)
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method drawHand(gr = Graphics, angle = double, radius = int, color = Color) public
    x2 = x1 + (int (radius * Math.cos(angle)))
    y2 = y1 + (int (radius * Math.sin(-angle)))
    gr.setColor(color)
    gr.drawLine(x1, y1, x2, y2)
    return
 
  -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  method actionPerformed(evt = ActionEvent) public
    repaint()
    return
 