【问题标题】:Scala Wrapper class by extending Component and with the SequentialContainer.Wrapper trait, do I have the correct understanding of traits?Scala Wrapper 类通过扩展 Component 和 SequentialContainer.Wrapper 特征,我对特征有正确的理解吗?
【发布时间】:2014-02-13 09:44:55
【问题描述】:

以下代码取自这篇文章: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,所以我对特性有点不确定。所以我一直听到的是,traits 就像多重继承,你可以混合和匹配它们?

我绘制了一个图表,表示 PopupMenu 在整个继承结构中的位置。澄清几点:

1) 似乎从 Component 覆盖了惰性 val peer:JComponent 并且还从 SequentialContainer.Wrapper 获取了 contents 属性? (紫色文字)对吗?

2) Sequential.Wrapper 也有一个抽象的 def 对等体:JComponent.. 但这不是被覆盖的那个,所以这里根本不使用它?

3) 令人困惑的是 Component 和 Sequential.Wrapper 有一些相同的属性:它们都有 def publish 和 def subscribe(红色文本).. 但是 popupMenu 将使用的是 Component 类的订阅/发布?

4) 为什么我们不能写 PopupMenu extends SequentialContainer.Wrapper 来代替 Component?

希望这不是一次太多的问题。非常感谢您的帮助,我是 Scala 的初学者..

【问题讨论】:

    标签: swing scala inheritance mixins traits


    【解决方案1】:

    我会根据你的问题数量来回答:

    1. 正确

    2. 正确。最上面的 trait 是 UIElement,它定义了一个 abstract 成员 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 通过说contents 是一个可变缓冲区(而不是只读序列)来改进Container。因此,它的实现SequentialContainer.Wrapper 混合了Container.Wrapper,但用标准的Scala 缓冲区替换了contents。还没有给出具体的peer。为方便起见,Component 确实实现了该成员,但正如您所见,最终类 PopupMenu 覆盖了 peer。由于类型系统的工作方式,所有参与的特征都可以访问peer,但只有PopupMenu“知道”该类型已被细化为javax.swing.JPopupMenu。比如SequentialContainer.Wrapper只知道有一个javax.swing.JComponent,所以可以使用peer的这部分API。

    3. Publisher 特征是由 UIElement 引入的,因此您会在派生自 UIElement 的所有类型中找到它。 在层次结构中多次出现相同的特征并没有错。在最后一个类中,Publisher 只有一个实例,不存在多个“版本”。 即使Publisher 没有在根中定义,但在例如@987654350 中独立定义@ 和SequentialContainer.Wrapper,你只会在最终类中获得一个实例。

    4. 这很简单。在 Scala 中,您只能扩展一个类,但可以混合任意数量的特征。 Component 是一个类,而其他所有东西都是特征。我是class A extends <trait-or-class> with <trait> with <trait> ...。


    总而言之,所有 GUI 元素都继承自 trait UIElement,后者由 java.awt.Component 支持。具有子元素的元素使用特征Container,所有允许您按特定顺序添加和删除元素的普通面板类型元素使用SequentialContainer。 (并非所有面板都有顺序,例如BorderPanel 没有)。这些是抽象接口,为了获得所有必要的实现,你有.Wrapper 类型。最后为了得到一个可用的类,你有Component,它扩展了UIElement,并且要求对等体是javax.swing.JComponent,所以它可以实现所有的标准功能。

    当你实现一个新的包装器时,你通常使用Component 并优化peer 类型,以便你可以访问该对等体的特定功能(例如JPopupMenu 的show 方法)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-11
      • 2015-06-03
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-26
      相关资源
      最近更新 更多