We often want a graphical user interface that updates itself, without any user interaction. That means that there is no event that causes the change in the user interface.
The solution is to make an event happen by setting an alarm clock. Such an alarm clock is called a timer. We specify how often we want the alarm to go off, and provide a function object that will be called by the alarm event, that is, every time the alarm rings.
Scala Swing does not include a timer class, so we have to use a Java timer. Here is a Scala object that makes using the Java timer a bit nicer:
object Timer { def apply(interval: Int, repeats: Boolean = true)(op: => Unit) { val timeOut = new javax.swing.AbstractAction() { def actionPerformed(e : java.awt.event.ActionEvent) = op } val t = new javax.swing.Timer(interval, timeOut) t.setRepeats(repeats) t.start() } }
We can create and start a timer that will go off every 2000 milliseconds and then print a line on the terminal like this:
Timer(2000) { println("Timer went off") }
If you want a timer that runs only once and then stops, set the repeats argument to false:
Timer(10000, false) { println("10 seconds are over!") }
Let's use this to create a clock that shows the real time, and which updates itself:
import scala.swing._ import java.awt.{Font,Color} object Time { private val form = new java.text.SimpleDateFormat("HH:mm:ss") def current = form.format(java.util.Calendar.getInstance().getTime) } object Timer { def apply(interval: Int, repeats: Boolean = true)(op: => Unit) { val timeOut = new javax.swing.AbstractAction() { def actionPerformed(e : java.awt.event.ActionEvent) = op } val t = new javax.swing.Timer(interval, timeOut) t.setRepeats(repeats) t.start() } } class UI extends MainFrame { title = "Clock #1" preferredSize = new Dimension(320, 160) private var lastTime = Time.current private val clock = new Label(lastTime) { foreground = new Color(0, 0, 160) font = new Font("SansSerif", Font.PLAIN, 64) } contents = clock Timer(200) { tick() } Timer(10000, false) { println("Clock has been running for 10 seconds!") } def tick() { // this method is called every 100 milliseconds val newTime = Time.current if (newTime != lastTime) { clock.text = newTime lastTime = newTime } } } object ClockOne { def main(args: Array[String]) { val ui = new UI ui.visible = true } }
Timers are not really good enough to program fast animations as in fast-moving computer games. To make a fast-moving user interface, you should create a thread that continually updates the game, writes the current graphics to a buffer, and then requests the user interface to update the display from this buffer. Ask me for more details or some example code if you want to do this in Scala.