Home

More than one element in the window

More than one element in the window

The contents of a scala.swing.Frame or scala.swing.MainFrame object is a single component. Typically, we want to show more things in a window than just a single label or a single button. That means that we have to worry about laying out multiple components.

Our next program, gui3.scala, uses a scala.swing.BoxPanel to arrange multiple components inside the window. So the window's (MainFrame's) contents is a BoxPanel, and the BoxPanel contains a label and two buttons:

import scala.swing._

class UI extends MainFrame {
  title = "GUI Program #3"
  contents = new BoxPanel(Orientation.Vertical) {
    contents += new Label("Look at me!")
    contents += Button("Press me, please") { println("Thank you") }
    contents += Button("Close") { sys.exit(0) }
  }
}

object GuiProgramThree {
  def main(args: Array[String]) {
    val ui = new UI
    ui.visible = true
  }
}
The assignment
  contents = new BoxPanel(Orientation.Vertical) {
    contents += new Label("Look at me!")
    contents += Button("Press me, please") { println("Thank you") }
    contents += Button("Close") { sys.exit(0) }
  }
creates a new object of a class that extends BoxPanel. The three lines that add a label and two buttons to the contents of this object form the constructor of this nameless class. We could instead have written the UI class like this:
class UI extends MainFrame {
  title = "GUI Program #3"
  val box = new BoxPanel(Orientation.Vertical)
  box.contents += new Label("Look at me!")
  box.contents += Button("Press me, please") { println("Thank you") }
  box.contents += Button("Close") { sys.exit(0) }
  contents = box
}
However, this style is less common in Scala.

The window looks like this:

Screenshot of GuiProgramThree

Note that the "Close" button now really closes the program. The "Press me, please" button still prints "Thank you", and the label does nothing.

If you change Orientation.Vertical to Orientation.Horizontal, the window will look like this:

Screenshot of GuiProgramThree with Orientation.Horizontal

This is all very dense and not so pretty, so lets add a border around the three components:
class UI extends MainFrame {
  title = "GUI Program #3"
  contents = new BoxPanel(Orientation.Vertical) {
    contents += new Label("Look at me!")
    contents += Button("Press me, please") { println("Thank you") }
    contents += Button("Close") { sys.exit(0) }
    border = Swing.EmptyBorder(10, 10, 10, 10)
  }
}
It will look like this (the four numbers indicate the top, left, right, and bottom border width in pixels):

Screenshot of GuiProgramThree with empty border

There are other styles of borders that you can try, such as
 
  border = Swing.BeveledBorder(Swing.Lowered)
  border = Swing.BeveledBorder(Swing.Raised)
  border = Swing.MatteBorder(10, 10, 10, 10, java.awt.Color.WHITE)
  border = Swing.TitledBorder(Swing.LineBorder(java.awt.Color.RED), "Fun")
  border = Swing.TitledBorder(Swing.EtchedBorder(Swing.Lowered), "Fun")
  border = Swing.CompoundBorder(Swing.BeveledBorder(Swing.Lowered),
                                Swing.EmptyBorder(10, 10, 10, 10))
You can find pictures of these borders on the Java website.

The buttons are still too close together. Also, what happens when you resize?

Screenshot of GuiProgramThree after resizing

That's quite ugly! We can improve the spacing by adding struts and glue between the visible components:
class UI extends MainFrame {
  title = "GUI Program #3"
  contents = new BoxPanel(Orientation.Vertical) {
    contents += new Label("Look at me!")
    contents += Swing.VStrut(10)
    contents += Swing.Glue
    contents += Button("Press me, please") { println("Thank you") }
    contents += Swing.VStrut(5)
    contents += Button("Close") { sys.exit(0) }
    border = Swing.EmptyBorder(10, 10, 10, 10)
  }
}

Screenshot of GuiProgramThree with struts and glue

A Swing.VStrut(a) is an empty component that is a pixels high (and has zero width). Similarly, a Swing.HStrut(a) is an empty component that is a pixels wide (and has zero height). A Swing.Glue takes no space, but it can extend as much as you want—try resizing the window now! (There are also Swing.HGlue and Swing.VGlue, which can extend only horizontally or vertically.)

We only discussed the BoxPanel here, but there are other useful panels that layout their elements in a different way: FlowPanel, BorderPanel, GridPanel, and GridBagPanel.