Following the discussion on
this
StackOverflow question, specifically Henri’s answer (hezamu), here’s what I’m doing on my current Vaadin + Scala project.
I’m not using scala-wrapper because when I started it was still in a very early stage, and also I wanted to improve my Scala by making my own wrapper.
My goal has been to create the
MINIMUM
amount of code to make Vaadin nicer to use in Scala.
Also, I’m relying
ONLY
on implicit conversions (aka pimp-my-library pattern), thus avoiding sub-classing Vaadin’s components.
Main implicits: defining listeners. Here’s a sample:
//button click listener
class PimpedButton[B <: {def addListener(listener:Button.ClickListener):Unit} ]
(btn:B ){
def onClick(fn: Button#ClickEvent => Unit):B = {
btn.addListener( new Button.ClickListener(){
def buttonClick(event:Button#ClickEvent) = fn(event)
})
btn
}
def onClick(fn: => Unit):B = {
btn.addListener( new Button.ClickListener(){
def buttonClick(event:Button#ClickEvent) = fn
})
btn
}
}
implicit def pimpButton[B <: {def addListener(listener:Button.ClickListener):Unit}]
(btn:B) = new PimpedButton(btn)
Using it:
val btn = new Button("do stuff") onClick {
//do some fancy logic here
}
Notes:
- I’m using duck typing, thus pimping any classes that define an addListener that accepts a ClickListener. This way I don’t have to keep track of what classes need this pimp.
- I’m returning the object on the onClick methods, this makes it more convenient to use directly on object creation
- I’m defining two onClick variants, one that receives the event object, and another without it, this is just for code simplicity when I don’t need the event object (which is most of the time)
I’m defining similar implicits for types that have:
addListener(listener : Property.ValueChangeListener)
addListener(listener : ItemClickListener)
addListener(listener : TextChangeListener)
addListener(listener : MouseEvents.ClickListener)
addListener(listener : FragmentChangedListener)
Another nice pimp, which I dubbed “anti-repetition”:
class PimpedAddComponent(obj:{def addComponent(c:Component):Unit}) {
def addComponents(comps:Component*) = comps foreach {c=>obj.addComponent(c)}
}
implicit def pimpAddComponent(obj:{def addComponent(c:Component):Unit}) = new PimpedAddComponent(obj)
The idea is to avoid this kind of boring repetition:
class SomeComponent {
addComponent(x)
addComponent(y)
addComponent(z)
}
and replace it with:
class SomeComponent {
addComponents(x,y,z)
}
much nicer
And adding collections of components comes for free, for example:
val l = List("label text 1","label text 2","label text 3")
addComponents(l map {new Label(_)} : _*)
I’ve created an implicit like this also for types defining:
addItem(a:Any)
That’s basically it (there’s a couple other things, like the Upload component listeners). It’s not much, but it’s enough to remove the most annoying boilerplate.
PS: maybe I should have put this up on GitHub or something, but I didn’t think it was worthy of such