title: Listeners and reactions in Scala Swing
body: <p>I've done a fair bit of searching and some trial and error in eclipse, but there seems to be a gap in my understanding of listeners and reactions when writing a GUI in Scala using Swing.</p>
  
  <p>Does each listener get a reactions block, or do I register listeners on all components that might generate an event and react to each on in a large reactions block with case statements?</p>
  
  <p>Where exactly do the listeners and reaction blocks belong.</p>
  
  <p>Here's an abbreviated version of my GUI code:</p>
  
  <pre><code>import scala.swing._
  import scala.swing.event.ButtonClicked
  import scala.swing.event.KeyTyped
  import scala.swing.event.KeyPressed
  
  object HumanGUI extends SimpleGUIApplication {
  
   val basicPane = new java.awt.Dimension(800, 200)
   val botPane = new java.awt.Dimension(400, 200)
   val felt = new java.awt.Color(35, 125, 35)
  
   def top = new MainFrame {
  
      title = "Blackjack GUI"
  
      val ConnectionPanel = new BoxPanel(Orientation.Vertical) {
        background = felt
        preferredSize = new java.awt.Dimension(155, 90)
        minimumSize = preferredSize
        maximumSize = preferredSize
  
        val ipAddressLabel = new Label("House IP:")
        ipAddressLabel.foreground = java.awt.Color.WHITE
        ipAddressLabel.horizontalTextPosition = scala.swing.Alignment.Left
  
        val portLabel = new Label("House port:")
        portLabel.foreground = java.awt.Color.WHITE
        portLabel.horizontalTextPosition = scala.swing.Alignment.Left
  
        val ipAddressTextField = new TextField
        val portTextField = new TextField
  
        contents += ipAddressLabel
        contents += ipAddressTextField
        contents += portLabel
        contents += portTextField
      }
  
      val DetailPanel = new BoxPanel(Orientation.Vertical) {
        background = felt
        preferredSize = new java.awt.Dimension(100, 160)
        minimumSize = preferredSize
        maximumSize = preferredSize
  
        val nameLabel = new Label("Your name:")
        nameLabel.foreground = java.awt.Color.WHITE
        nameLabel.horizontalTextPosition = scala.swing.Alignment.Left
  
        val bankrollLabel = new Label("Bankroll:")
        bankrollLabel.foreground = java.awt.Color.WHITE
        bankrollLabel.horizontalTextPosition = scala.swing.Alignment.Left
  
        val betLabel = new Label("Bet:")
        betLabel.foreground = java.awt.Color.WHITE
        betLabel.horizontalTextPosition = scala.swing.Alignment.Left
  
        val nameTextField = new TextField
        val bankrollTextField = new TextField
        val betTextField = new TextField
  
        val goButton = new Button("Go!")
  
        contents += nameLabel
        contents += nameTextField
        contents += bankrollLabel
        contents += bankrollTextField
        contents += betLabel
        contents += betTextField
        contents += goButton
      }
  
      val PlayPanel = new BoxPanel(Orientation.Vertical) {
        background = felt
        val hitButton = new Button("Hit")
        val stayButton = new Button("Stay")
        val doubleButton = new Button("Double")
        val quitButton = new Button("Quit")
  
        contents += hitButton
        contents += stayButton
        contents += doubleButton
        contents += quitButton
      }
  
      val playerPanel = new BoxPanel(Orientation.Horizontal) {
        background = felt
        border = new javax.swing.border.LineBorder(java.awt.Color.WHITE)
        preferredSize = basicPane
        minimumSize = basicPane
        maximumSize = basicPane
        opaque = true
  
        contents += ConnectionPanel
        contents += DetailPanel
        contents += PlayPanel
      }
  
      contents = new BoxPanel(Orientation.Vertical) {
        contents += playerPanel
      }
    }
  }
  </code></pre>
  
  <p>So the question is where do I put my listeners and reaction blocks?<br>
  I want to react to the buttons in PlayPanel, and the text fields in both ConnectionPanel and DetailPanel.<br>
  Do I put the listeners and reaction blocks as close to the elements that I'm interested as possible, or do I put a big block of listeners and reactions at the end of the MainFrame section?<br>
  Does it even matter?</p>
  
  <p><strong><em>EDIT</em></strong><br>
  I've made significant progress and have much of what I need working, along with a better understanding of the concepts I wasn't getting before.  </p>
  
  <p>This excerpt from Odersky's "Programming in Scala" was what helped me the most.  Specifically, the example from this page:  </p>
  
  <p><a href="http://www.artima.com/pins1ed/gui-programming.html" rel="nofollow noreferrer">http://www.artima.com/pins1ed/gui-programming.html</a>  </p>
  
  <p>The code is from the first edition of the text, so I question whether or not there's a better way in Scala 2.9, but it was clear an concise and summed up what I was misunderstanding.  </p>
  
  <p>From the example, which is a simple fahrenheit to celsius converter, I came to understand that the listener and the reactions blocks belongs after the contents block for the MainFrame.</p>
  
  <p>so I ended up with:</p>
  
  <pre><code>object HumanGUI extends SimpleSwingGUIApplication {
    def top = new MainFrame {
      title = "My Blackjack GUI"
  
      //The fields I want to work with are instantiated as object
      object ipAddressTextField extends TextField { columns = 15 }
      object portNumberTextField extends TextField {columns = 5 }
  
      //other panels, objects, etc would go here
      val OtherPanel = new BoxPanel(Orientation.Horizontal) {
         label = "Other Panel"
      }
  
      //and here we have the contents += block for the mainframe, other panels, etc from 
      //above would be added to the main frame here
      contents = new BoxPanel(Orientation.Vertical) {
        contents += ipAddressTextField
        contents += portNumberTextField
      }
  
      //here's the listen to, listening on the object created above, and it's enclosed in 
      //in backticks, a good explanation of that is found in the link below
      listenTo(`ipAddressTextField`)
      reactions += {
        case EditDone('ipAddressTextField`) =&gt;
          //do something!
      }
    }
  </code></pre>
  
  <p><a href="https://stackoverflow.com/questions/6576594/need-clarification-on-scala-literal-identifiers-backticks">Need clarification on Scala literal identifiers (backticks)</a>  </p>
  
  <p>So it seems that the answer to my question is that the listenTo and reactions blocks belong in the MainFrame block, but should appear after it's contents += { //contents } block.</p>
  
  <p>Additional trial and error in eclipse shows that while this solution works for me, there is clearly much more that I don't understand.  For example, while I was unable to get listeners for KeyPress events to work if I tried to listen and react to them in within the<br>
      val OtherPanel = new BoxPanel(Orientation.Horizontal) { }<br>
  portion of the above code, I was able to get a button registered and working like this:  </p>
  
  <pre><code>val OtherPanel = new BoxPanel(Orientation.Horizontal) {
    val betLabel = new Label("Bet:")
    val betTextField = new TextField
    val goButton = new Button("Go!")
  
    listenTo(goButton)
    reactions += {
      case ButtonClicked(b) =&gt;
        betTextField.text = "Go!"
    }
  
    contents += betLabel
    contents += betTextField
    contents += goButton
  }
  </code></pre>
  
  <p>Why this worked but my attempts to do something along the lines of </p>
  
  <pre><code>val OtherPanel = new BoxPanel(Orientation.Horizontal) {
    val betLabel = new Label("Bet:")
    val betTextField = new TextField
    val goButton = new Button("Go!")
  
  listenTo(betTextField)
  reactions += {
    case KeyTyped(betTextField, Enter, _, _) =&gt; {
      println("Caught enter")
    }
  
    contents += betLabel
    contents += betTextField
    contents += goButton
  }
  </code></pre>
  
  <p>didn't work is still baffling me.  I'm assuming that it should work and I'm just doing something wrong.  Perhaps that melding that approach with a case EditDone instead of a case KeyTyped(<em>,</em>,<em>,</em>) would have worked but I'm a little too burnt out right now to follow up on that.</p>
  
  <p>I haven't accepted an answer yet because I'm hoping that someone who sees this can clarify the points I still don't understand.  Should that not happen and the question remain unanswered for a few days I will likely accept @som-snytt's answer as his code was very helpful.</p>