如何使用scala将监听器添加到javafx UI组件

时间:2012-10-30 10:17:24

标签: swing scala javafx-2 javafx observer-pattern

我使用Scala和Publisher特征来监听我的数据组件的更改并发布/更新显示以摆动UI组件(如this

我最近重写了我的程序以使用Javafx2Scala,我无法使用最近的绑定项目Scalafx,因为只有部分程序切换到javafx(这是嵌入摇摆JFrame)。

我可以在scala中使用哪种最佳语法来获得基于scala.swing Publisher特征的相同(或类似)行为?

您是否有一些链接或简单示例来说明此方法?

1 个答案:

答案 0 :(得分:1)

目前我建议的是重复使用实现发布/反应系统的scala.swing模式。 可以从旧scala.swing存储库中的scala.swing.Component获取示例。

我们的想法是为需要发布事件的所有 javafx 类创建可能最通用的包装器,并将这些类隐式转换为此包装器。

包装器将定义用于将事件从 javafx 侦听器桥接到发布/响应系统的逻辑。

示例代码看起来像这样,并且基于前面提到的scala.swing代码

  package scala.fx.react

  object ScalaFxReactive {
      /*
       * Can't say if Node is the best and only class that should be converted.
       * You should make implicit publishers from any fx class that supports the
       * addEventHandler(someEventType)
       */
      implicit def toPublisher(peer: Node): ScalaFxComponentPublisher = new ScalaFxComponentPublisher(peer)

  class ScalaFxComponentPublisher(peer: Component) {

    /**
     * Contains publishers for various mouse events. They are separated for
     * efficiency reasons.
     */
    object mouse {
       /**
        * Publishes clicks, presses and releases.
        */
        val clicks: Publisher = new LazyPublisher {

          lazy val clicked = new EventHandler[MouseEvent] {
            def handle(e: MouseEvent) {
               /*
                *This is the most critical part: you need
                * to check if it's possible to create the swing 
                * event from an fx event, eventually through an
                * implicit conversion
                */
               publish(new MouseClicked(e))
            }
          }

          def onFirstSubscribe() = peer.setOnMouseClicked(clicked)
          def onLastUnsubscribe() = peer.setOnMouseClicked(null)
          /*
           * probably better:
           * def onLastUnsubscribe() = peer.removeEventHandler(MouseEvent.MOUSE_CLICKED)
           */
        }
        /**
         * Publishes enters, exits, moves, and drags.
         */
        val moves: Publisher = new LazyPublisher {
           lazy val entered = new EventHandler[MouseEvent] {
             def handle(e: MouseEvent) {
               publish(new MouseEntered(e))
             }
           }
           lazy val exited = new EventHandler[MouseEvent] {
             def handle(e: MouseEvent) {
               publish(new MouseExited(e))
             }
           }

           /*
            * Need implementation
            */
           lazy val moved = new EventHandler[MouseEvent] {
             ...
           }
           def onFirstSubscribe() {
             peer.setOnMouseEntered(entered)
             peer.setOnMouseExited(exited)
             ...
           }
           def onLastUnsubscribe() {
             peer.setOnMouseEntered(null)
             peer.setOnMouseExited(null)
             ...
           }
         }
       }
     }

然后,您可以像对scala.swing

一样支持在组件中做出反应
class MyComponent {
    import scala.fx.react.ScalaFxReactive._

    listenTo(node)

    reactions += {
      ...   
    }

}

代码将被视为草图,不会按原样编译。它指出了一个可能的方向,但完整的解决方案对于那些像您一样需要逐步将遗留scala.swing应用程序桥接到javafx库的人来说可能是一个非常有趣的库。