In this post I want to expand that example by showing you how to select a ComboBox item programmatically and also listen to changes to the ComboBox.
The code below shows how to change the ComboBox selection programmatically.
This code is very similar to before so I won't bother explaining it again. The difference is what happens when the button is clicked. The code called is:
import swing.Swing._
import swing._
import event.{ButtonClicked, WindowClosing}
import swing.ListView._
class ScalaSwingDemo2 extends Frame {
title = "Scala Swing Demo 2"
case class OS(name:String, version:String)
val snowLeopard = OS("Snow Leopard", "10.6.3")
val comboBox = new ComboBox(List(OS("Ubuntu", "10.04"), snowLeopard, OS("Windows", "7"))) {
renderer = Renderer(_.name)
}
val button = new Button {
text = "Select Snow Leopard OS"
}
contents = new FlowPanel {
contents += new Label("Select OS:")
contents += comboBox
contents += button
}
listenTo(button)
reactions += {
case WindowClosing(e) => System.exit(0)
case ButtonClicked(`button`) => comboBox.selection.item = snowLeopard
}
pack
centerOnScreen
visible = true
}
object ScalaSwingDemo2Runner {
def main(args: Array[String]) {
onEDT(new ScalaSwingDemo2)
}
}
comboBox.selection.item = snowLeopard
This sets the selected item of the ComboBox to the specified OS class, in this case Snow Leopard. Notice that it is expecting a class of type OS without casting. This is statically checked and I can prove this by changing the line to:
comboBox.selection.item = "Snow Leopard"
If you try and compile this you will get a compile time error.
This is very simple but is just another example of how concise Scala can be.
The next bit of code shows how to listen to selection changes on the ComboBox.
We've added another reaction to our Frame and told our Frame to listen to another publisher. We want to listen to the selection of the ComboBox so achieve this with this line:
import swing.Swing._
import swing._
import event.{SelectionChanged, ButtonClicked, WindowClosing}
import swing.ListView._
class ScalaSwingDemo3 extends Frame {
title = "Scala Swing Demo 3"
case class OS(name:String, version:String)
val snowLeopard = OS("Snow Leopard", "10.6.3")
val comboBox = new ComboBox(List(OS("Ubuntu", "10.04"), snowLeopard, OS("Windows", "7"))) {
renderer = Renderer(_.name)
}
val button = new Button {
text = "Select Snow Leopard OS"
}
contents = new FlowPanel {
contents += new Label("Select OS:")
contents += comboBox
contents += button
}
listenTo(button)
listenTo(comboBox.selection)
reactions += {
case WindowClosing(e) => System.exit(0)
case ButtonClicked(`button`) => comboBox.selection.item = snowLeopard
case SelectionChanged(`comboBox`) => {
val selectedOS = comboBox.selection.item
println("Selected OS Name: " + selectedOS.name + " Version: " + selectedOS.version)
}
}
pack
centerOnScreen
visible = true
}
object ScalaSwingDemo3Runner {
def main(args: Array[String]) {
onEDT(new ScalaSwingDemo3)
}
}
listenTo(comboBox.selection)
When a user selects a different item in the ComboBox, the block of code after the case SelectionChanged(`comboBox`) => is run. In this case the block of code just prints out information about the selected item.
The button functionality is still available. If you click the button (when Snow Leopard is not selected), you will see that Snow Leopard is selected, and the SelectionChanged block is run. This is what you would expect. However, when selecting something programmatically, sometimes you would not want that block of code to be run. Scala Swing provides an easy way to deal with this, which the following code demonstrates.
Here, when the button is clicked, before we select the snowLeopard item, we tell the frame to be deaf to the ComboBox selection with this line of code:
import swing.Swing._
import swing._
import event.{SelectionChanged, ButtonClicked, WindowClosing}
import swing.ListView._
class ScalaSwingDemo4 extends Frame {
title = "Scala Swing Demo 4"
case class OS(name:String, version:String)
val snowLeopard = OS("Snow Leopard", "10.6.3")
val comboBox = new ComboBox(List(OS("Ubuntu", "10.04"), snowLeopard, OS("Windows", "7"))) {
renderer = Renderer(_.name)
}
val button = new Button {
text = "Select Snow Leopard OS"
}
contents = new FlowPanel {
contents += new Label("Select OS:")
contents += comboBox
contents += button
}
listenTo(button)
listenTo(comboBox.selection)
reactions += {
case WindowClosing(e) => System.exit(0)
case ButtonClicked(`button`) => {
deafTo(comboBox.selection)
comboBox.selection.item = snowLeopard
listenTo(comboBox.selection)
}
case SelectionChanged(`comboBox`) => {
val selectedOS = comboBox.selection.item
println("Selected OS Name: " + selectedOS.name + " Version: " + selectedOS.version)
}
}
pack
centerOnScreen
visible = true
}
object ScalaSwingDemo4Runner {
def main(args: Array[String]) {
onEDT(new ScalaSwingDemo4)
}
}
deafTo(comboBox.selection)
Once the item has been selected we want to listen to the selection again so call:
listenTo(comboBox.selection)
That's it for this post. I hope Java Swing developers recognise what I'm doing here and how much easier it is when using Scala Swing. Remember as well, I'm only using the standard Scala Swing library.
To make the comboBox editable, I changed comboBox declaration this way:
ReplyDeleteval comboBox = new ComboBox(List(OS("Ubuntu", "10.04"), snowLeopard, OS("Windows", "7"))) {
implicit def editor(c: ComboBox[OS]): ComboBox.Editor[OS] =
new ComboBox.BuiltInEditor(this)(
s => OS(s,"no version"), // could split s with a possible comma separator
os => os.name) {}
makeEditable();
// renderer = Renderer(_.name)
renderer = Renderer(_.toString)
}
It took me quite some time to figure out the editor defintion.
But, after entering "Solaris" in the box, it gets transformed thus:
OS(OS(Solaris,no version),no version)