问题
I'm trying to understand how the following class works taken from an answer from this thread: Scala Popup Menu
Since the thread is pretty old I decided to just start a new question. I'm new to Scala with a Java background and I'm wondering how this class works. I read that an object with the same name as a class is like a class with a singleton object? I'm not sure how this fits in to achieving the wrapper though.. (why do we need the object?)
And what exactly does the SuperMixin trait do? The API says "This trait is used to redirect certain calls from the peer to the wrapper and back. Useful to expose methods that can be customized by overriding." which doesn't do a very good job of explaining to a beginner.
I would really appreciate it if someone can help explain to a beginner how this class and object (it seems to me, magically) get me a wrapper class for the JPopupMenu and lets me call the show method which makes a popupMenu appear on the screen.. and it also seems like I can set its content (contents+= some scala.swing.menuItem) without it being defined in the class below?
import javax.swing.JPopupMenu
import scala.swing.{ Component, MenuItem }
import scala.swing.SequentialContainer.Wrapper
object PopupMenu {
private[PopupMenu] trait JPopupMenuMixin { def popupMenuWrapper: PopupMenu }
}
class PopupMenu extends Component with Wrapper {
override lazy val peer: JPopupMenu = new JPopupMenu with PopupMenu.JPopupMenuMixin with SuperMixin {
def popupMenuWrapper = PopupMenu.this
}
def show(invoker: Component, x: Int, y: Int): Unit = peer.show(invoker.peer, x, y)
/* Create any other peer methods here */
}
回答1:
The companion object for PopupMenu
doesn't serve any specific purpose here except functioning as a name space for the auxiliary trait JPopupMenuMixin
. This trait can then be "hidden" by making it private[PopupMenu]
, so it is only known by class PopupMenu
and its companion object.
Frankly, I don't see the purpose of that trait. It defines a method popupMenuWrapper
pointing to the outer Scala Swing component, but that method is not used at all. So a less confusing version would be simply:
import scala.swing._
import javax.swing.JPopupMenu
class PopupMenu extends Component with SequentialContainer.Wrapper {
override lazy val peer: JPopupMenu = new JPopupMenu with SuperMixin
def show(invoker: Component, x: Int, y: Int): Unit = peer.show(invoker.peer, x, y)
}
Test:
val pop = new PopupMenu {
contents += new MenuItem("Foo")
}
lazy val but: Button = Button("Test") {
pop.show(but, 0, 0)
}
val f = new Frame {
contents = but
pack().centerOnScreen()
open()
}
The only thing necessary for a wrapper is to extend scala.swing.Component
and override the peer
value with the underlying javax.swing
component. The mixin with SuperMixin
overrides a few methods of that component, such as paintComponent
, in order to forward them to the outer wrapper component. That's all.
The wrapper mixes in SequentialContainer.Wrapper
which allows for the contents +=
operation to add the menu items.
来源:https://stackoverflow.com/questions/21727586/how-to-create-scala-swing-wrapper-classes-with-supermixin