Scala Swing Ken Scambler
Origins of Swing  Java’s main desktop programming environment
Single Threaded, MVC framework
Developed from Abstract Windowing Toolkit (AWT) in the late 90s
Sun has focused on the web rather than desktop
Has faded from the limelight
However still has many users and devotees
Swing’s Advantages Cross-platform (mostly!)
Extremely powerful
Flexible
Extensible
Uses hardware acceleration
Comparable to native performance (nowadays!)
Swing’s Disadvantages Huge, complex API
Requires very verbose code
Events require anonymous inner class gymnastics!
Doesn’t integrate with Collection API
Models aren’t typesafe
Introducing Scala Swing Thin wrapper framework
Far less code
Dramatically simpler API
Full integration with Scala Collections
Introducing Scala Swing Scala getter/setter properties
Events use pattern-matching and partial functions
Performance is just as good
Panels & Layouts Layouts are built into the panel

Scala+swing

  • 1.
  • 2.
    Origins of Swing Java’s main desktop programming environment
  • 3.
  • 4.
    Developed from AbstractWindowing Toolkit (AWT) in the late 90s
  • 5.
    Sun has focusedon the web rather than desktop
  • 6.
    Has faded fromthe limelight
  • 7.
    However still hasmany users and devotees
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
    Comparable to nativeperformance (nowadays!)
  • 14.
  • 15.
  • 16.
    Events require anonymousinner class gymnastics!
  • 17.
  • 18.
  • 19.
    Introducing Scala SwingThin wrapper framework
  • 20.
  • 21.
  • 22.
    Full integration withScala Collections
  • 23.
    Introducing Scala SwingScala getter/setter properties
  • 24.
    Events use pattern-matchingand partial functions
  • 25.
  • 26.
    Panels & LayoutsLayouts are built into the panel
  • 27.
  • 28.
    Add components with'contents' buffer
  • 29.
    FlowPanel new FlowPanel { contents += new Button( "A" ) contents += new Button( "B" ) contents += new Button( "C" ) contents += new Button( "D" ) }
  • 30.
    GridPanel new GridPanel(3,3) { contents ++= 1 to 9 map ( n => new Button(n.toString)) }
  • 31.
    BorderPanel new BorderPanel { import BorderPanel.Position._ layout( new Button( "West" )) = West layout( new Button( "Center" )) = Center layout( new Button( "North" )) = North }
  • 32.
    Events No moreXXXListeners!
  • 33.
  • 34.
    Event handlers arePartialFunctions which pattern match on events
  • 35.
    Classes which emitevents have the Publisher trait
  • 36.
    Classes which listento Publishers have the Reactor trait.
  • 37.
    Publishers & Reactorstrait Reactor { val reactions: Reactions def listenTo(ps: Publisher*): Unit def deafTo(ps: Publisher*): Unit } trait Publisher extends Reactor { def publish(e: Event): Unit listenTo( this ) }
  • 38.
    ButtonClicked events new FlowPanel { // Panels are Reactors // Buttons are Publishers val button = new Button( "abc" ) listenTo(button) reactions += { case ButtonClicked(b) => println( "Clicked " + b.text) } //... }
  • 39.
    ButtonClicked events // All publishers are reactors // that listen to themselves new Button( "abc" ) { reactions += { case ButtonClicked(b) => println( "Clicked " + b.text) } }
  • 40.
    Mouse Events new FlowPanel { val pub = new FlowPanel listenTo( pub .mouse.clicks, pub .mouse.moves, pub .mouse.wheel) reactions += { case me: MouseClicked => case me: MouseDragged => case me: MouseEntered => case me: MouseExited => case me: MouseMoved => case me: MouseWheelMoved => } }
  • 41.
    Selection Events new FlowPanel { val fruitList = List( "apples", "bananas", "pears" ) val listView = new ListView(fruitList ) listenTo( listView .selection) reactions += { case SelectionChanged(`fruitList`) => } }
  • 42.
    ListViews class ListView[A] extends Component { def this (items: Seq[A]) = //... //... }
  • 43.
    ListViews case class City(name: String, country: String, population: Int , capital: Boolean ) val items = List( City( "Lausanne" , "Schweiz" , 129273, false ), City( "Paris" , "France" , 2203817, true ), City( "New York" , "USA" , 8363710 , false ), City( "Berlin" , "Germany" , 3416300, true ), City( "Tokyo" , "Japan" , 12787981, true )) val view = new ListView(items) val cityNames = view.selection.items.map(_.name)
  • 44.
    Renderers From thelast example... val view = new ListView(items) { renderer = ListView.Renderer(_.name) } From the last example...
  • 45.
    Custom Painting val panel = new Panel { background = Color.blue override protected def paintComponent(g: Graphics2D) { super .paintComponent(g) g setColor Color.red for (x <- 0 until size.width by 10) g.drawLine(x, 0, x, size.height) } }
  • 46.
    Fun with mixinstrait BlueBackground { this : Panel => background = Color.blue} trait BlackBackground { this : Panel => background = Color.black} trait VerticalLines extends Panel { override protected def paintComponent(g: Graphics2D) { super .paintComponent(g) g setColor Color.red for (x <- 0 until size.width by 10) g.drawLine(x, 0, x, size.height) } } trait HorizontalLines extends Panel { override protected def paintComponent(g: Graphics2D) { super .paintComponent(g) g setColor Color.white for (y <- 0 until size.height by 20) g.drawLine(0, y, size.width, y) } } trait Blobs extends Panel { override protected def paintComponent(g: Graphics2D) { super .paintComponent(g) g setColor Color.green for (x <- 0 until size.width by 20; y <- 0 until size.height by 40) g.fillOval(x-4, y-4, 8, 8) } }
  • 47.
    Fun with mixinsval panel = new Panel with BlueBackground with HorizontalLines with VerticalLines with Blobs
  • 48.
    Fun with mixinsval panel = new Panel with BlackBackground with Blobs with VerticalLines with HorizontalLines
  • 49.
    A basic completeapp object SwingTalk extends SimpleSwingApplication { def top = new MainFrame { contents = new GridPanel(1, 4) { val nameLabel = new Label( &quot;Name&quot; ) val nameText = new TextField val helloButton = new Button( &quot;Say Hello&quot; ) val goodbyeButton = new Button( &quot;Say Goodbye&quot; ) listenTo(helloButton, goodbyeButton) contents ++= nameLabel :: nameText :: helloButton :: goodbyeButton :: Nil reactions += { case ButtonClicked(`helloButton`) => Dialog.showMessage(nameLabel, &quot;Hello, &quot; + nameText.text) case ButtonClicked(`goodbyeButton`) => Dialog.showMessage(nameLabel, &quot;Goodbye, &quot; + nameText.text) } } } }
  • 50.
    What's missing? Workin progress Drag N' Drop
  • 51.
  • 52.
    Better actor supportfor multi-threading EPFL are snowed under!
  • 53.
    Community contributions willmake a big difference
  • 54.