2

I am trying to implement a simple application in which I can write an item in Textfield and then entering a button which in turn reacting by inserting that item in a combo box.

However, I am facing a problem that the scala combobox swing is not mutable(I guess)?

Is there any way to make a combo mutable using scala swing?

import scala.swing._
import scala.swing.event._
import scala.swing.BorderPanel.Position._

object ReactiveSwingApp extends SimpleSwingApplication {
  def top = new MainFrame {
    title = "Reactive Swing App"

    val button = new Button {
      text = "Add item" 
    }   
    var textfield = new TextField {
      text = "Hello from a TextField"
    }

    var items = List("Item 1","Item 2","Item 3","Item 4")
    val combo = new ComboBox(items)

    contents = new BorderPanel {
      layout(new BoxPanel(Orientation.Vertical) {
          contents += textfield 
          contents += button
          contents += combo   
          border = Swing.EmptyBorder(30, 30, 10, 30)
      }) = BorderPanel.Center
    }

    listenTo(button, textfield)
    reactions += {
      case ButtonClicked(button) =>
        // var items1 = textfield.text :: items  <- how can a read Item be inserted
    }
  }
}
0__
  • 66,707
  • 21
  • 171
  • 266
MMAB
  • 47
  • 6
  • See also [*Using an Editable Combo Box*](http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#editable). – trashgod Mar 28 '13 at 17:17

2 Answers2

3

You are correct, the Scala-Swing ComboBox wrapper for JComboBox has a static model which does not allow additions or removals. Unfortunately, there are quite a few things in Scala-Swing which are less capable than the underlying Java-Swing components.

The good thing however is that each Scala-Swing component has a Java-Swing peer field, which you can use to patch the missing bits. I think the easiest is to create a thin wrapper for javax.swing.DefaultComboBoxModel, like:

class ComboModel[A] extends javax.swing.DefaultComboBoxModel {
  def +=(elem: A) { addElement(elem) }
  def ++=(elems: TraversableOnce[A]) { elems.foreach(addElement) }
}

Then your construction becomes

val combo = new ComboBox(List.empty[String])
val model = new ComboModel[String]
model ++= items
combo.peer.setModel(model)  // replace default static model

And your reaction

reactions += {
  case event.ButtonClicked(button) =>
    model += textfield.text
}
0__
  • 66,707
  • 21
  • 171
  • 266
1

At "0___" have you tested your code? It seems to have some Mismatch issues. I'm using scala 2.10.

Actually there is a way to work around the problem without having to handle the ComboBoxModel. Here is a short example:

class ComboBox(items: Array[String])
extends scala.swing.Component with java.awt.event.ActionListener with Publisher{

  override lazy val peer = new JComboBox(items)

  def +=(item: String) = peer.addItem(item)
  def -=(item: String) = peer.removeItem(item)
  def item = peer.getSelectedItem.asInstanceOf[String]
  def reset{peer.setSelectedIndex(0)}
  //additional methods

  //since its peer val is now a JComboBox

  peer.addActionListener(this)
  def actionPerformed(e: ActionEvent){
    //how to react once the selection changes
  }

  //since its also a scala.swing.Component extender
  listenTo(mouse.clicks) //and all the rest of the Publishers
  reactions += {
    case e: MouseClicked => //do something awesome
  }

  /* Also one could additionally extend the scala.swing.Publisher Trait
   * to be able to publish an event from here.
   */
  publish(MyEvent(item))
}

case class MyEvent(item: String) extends Event
tapmeppe
  • 41
  • 2
  • 8