以下代码来自这篇文章:How to create Scala swing wrapper classes with SuperMixin?
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)
}
我一直在尝试制作自定义包装器,所以需要理解这一点,这很简单但是从那以后 我只是开始熟悉Scala,所以我对性状有点不确定。所以我听到的是,特征就像多重继承,你可以混合搭配吗?
我画了一个图表,表示PopupMenu在整个继承结构中的位置。只是为了澄清一些事情:
1)它似乎覆盖了lazy val peer:来自Component的JComponent,还从SequentialContainer.Wrapper获取contents属性? (紫色文字)是吗?
2)Sequential.Wrapper还有一个抽象的def peer:JComponent ..但是这不是被覆盖的那个,所以这里根本没有使用它?
3)令人困惑的是Component和Sequential.Wrapper有一些相同的属性:它们都有def发布和def订阅(红色文本)..但是popupMenu将使用的是来自Component类的subscribe / publish ?4)为什么我们不能写PopupMenu而是用Component扩展SequentialContainer.Wrapper?
希望一下子问题不是太多。非常感谢帮助,我是Scala的初学者..
答案 0 :(得分:2)
我会回答你的问题:
正确
正确。最高特征是UIElement
,它定义了抽象成员def peer: java.awt.Component
。然后你有Container
只需添加 abstract 成员def contents: Seq[Component]
就可以读取子组件。 Container.Wrapper
是Container
的具体实现,它假设(抽象地)Java对等体是javax.swing.JComponent
。请注意,在Java自己的层次结构中,javax.swing.JComponent
是java.awt.Component
的子类型,因此没有冲突。子类型可以细化其成员的类型(“协方差”)。 SequentialContainer
通过说Container
是可变缓冲区(而不是只读序列)来优化contents
。因此,其实现 SequentialContainer.Wrapper
混合在Container.Wrapper
中,但用标准的Scala缓冲区替换contents
。在任何时候都没有给出具体的peer
。为方便起见,Component
确实实现了该成员,但正如您所见,最终的类PopupMenu
会覆盖peer
。由于类型系统的工作方式,所有参与的特征都可以访问peer
,但只有PopupMenu
“知道”该类型已被细化为javax.swing.JPopupMenu
。例如SequentialContainer.Wrapper
只知道有javax.swing.JComponent
,因此可以使用对等API的这一部分。
Publisher
特征由UIElement
引入,因此您可以在UIElement
派生的所有类型中找到它。 在层次结构中多次出现相同的特征没有任何问题。在最后一个类中,只有Publisher
的一个实例,它不存在多个“版本”。即使Publisher
尚未在根目录中定义,但独立于例如Component
和SequentialContainer.Wrapper
,您只能在最后一个类中获得一个实例。
这很简单。在Scala中,您只能扩展一个类,但可以混合任意数量的特征。 Component
是一个类,而其他所有其他东西都是特征。这是class A extends <trait-or-class> with <trait> with <trait> ...
。
总而言之,所有GUI元素都继承自UIElement
备份的特征java.awt.Component
。具有子元素的元素使用特征Container
,并且允许您按特定顺序添加和删除元素的所有普通面板类型元素都使用SequentialContainer
。 (并非所有面板都有顺序,例如BorderPanel
没有)。这些是抽象接口,为了获得所有必要的实现,您拥有.Wrapper
类型。最后,为了获得一个可用的类,你有Component
扩展UIElement
并要求对等体为javax.swing.JComponent
,因此它可以实现所有标准功能。
当您实现新的包装器时,通常使用Component
并优化peer
类型,以便您可以访问该对等方的特定功能(例如show
JPopupMenu
方法1}})。