文档章节

新手上路,各种记录: Scala Swing

aiasfina
 aiasfina
发布于 2012/12/28 09:54
字数 1136
阅读 511
收藏 1

一直都想做一下 C/S,但是没什么机会。这几天趁着有空玩了一下唯一接触过一点的 Swing,顺便总结总结。话说,绝大部分时间花在了代码着色上了,结果无功而返哈,笑:)

话说,这篇文章就在这连半成品都不算的小应用上写的呢。中间一直想换成 docat webapp 来写,担心出了神马毛病整篇文章就都完了。:P

首先给个应用截图:

在此输入图片描述

这是一个即时预览的 Markdown 编辑器,功能非常的少,开发的时间也没两天,基于 Scala Swing。

#####下面是代码结构:

在此输入图片描述

你会发现我几乎把所有的组件都拆开了,这是因为因为个人比较喜欢把组件描述放在父容器中,而组件的逻辑都独立出来。但是这样导致了一个问题,我稍后再讲。


###Swing 多线程

首先要说的是一个很不起眼的地方,那就是 Swing 多线程。

基于 Scala 如果不用多线程就没啥意思了,但很不凑巧的是 Swing 本身是单线程的。有关UI、事件派发的操作都需要由 Swing 分发。Java 的 invokeLater 在 Scala 的 Actor 上是行不通。

但是,我们可以设置 Actor 调度器来做到这点:继承 Actor 的 class 或 object 需要手动覆盖调度器。

<!-- lang: scala -->
object EventMonitorAct extends Actor {

    override val scheduler = new SchedulerAdapter {
        def execute(fun: => Unit) { Swing.onEDT(fun) }
     }
 }

另外acotr {} 方法是默认使用父调度器的,而我们在入口处就已经将初始化方法交给 Swing调度器来处理了:

<!-- lang: scala -->
object Marky {
    def main(args: Array[String]) = Swing.onEDT { startUp(args) }

    def startUp(args: Array[String]) { //... }
 }

其实我是在看到 invokeLater 才知道 Swing 单线程这回事的(典型零基础),至于 Scala 调度器?那是翻 Scala Swing 源码翻出来的,所以或许大概极有可能不是这样 = =

###Reactor/Publisher

Reactor/Publisher 是 Scala Swing 的亮点,非常简便的使用方式和扩展能力。只要在任何对象 混入(mixin) Reactor,你就可以监听组件的事件了。

但是,有一点令我很不爽,这种模型会侵入到各个组件,我需要把 Publisher 传到 Reactor 中。比如:在菜单里点击打开文件,然后将内容插入到编辑区中并改变标题。那么我需要在 Frame 和 EditorPane 中监听 MenuBar 的事件,或者将它们都写在一起。(如果你有其他方法还请告知..)

然后,就有下一个题目了。

###事件订阅/广播

在此输入图片描述

这是一个通用模块,可以用在任何对象。当发布者向事件中心发送一个消息,所有的订阅这都会得到这个消息并选择处理或丢弃。

拿上面那个例子来说:当在 MenuBar 中点击打开文件,该组件就只负责打开一个文件选择窗口并得到选中文件对象,MenuBar 只需做到这里就完成了它的职责,然后向事件中心发送一个名为 openfile 的消息并附带一个 File 对象的数组。只要任何一个订阅者响应这个 openfile 消息就能获得 File对象并且自动调用相应代码。

####菜单 MenuDef

<!-- lang: scala -->
    // 混入 Publishable 
trait MenuDef extends I18N with Publishable { this: MenuBar =>
   /*
    * File menu
    */
  val _new = new MenuItem(t("new"))
  val _open = new MenuItem(t("open"))
  val _save = new MenuItem(t("save"))
  val _quit = new MenuItem(t("quit"))

  contents += new Menu(t("file")) {
      contents += _new
      contents += _open
      contents += _save
      contents += new Separator
      contents += _quit
    }

    listenTo(_new, _open, _save, _quit)
    reactions += {
       case ButtonClicked(`_open`) =>
           val chooser = new FileChooser
           chooser.showOpenDialog(this)
           val file = chooser.selectedFile
           if (file != null)
              fire('openfile, Array(MdFile(file)))    //发布 openfile消息,附带参数数组
    }
}

####编辑器 Editor.scala:

<!-- lang: scala -->
class Editor extends EditorPane with I18N with Publishable with Listenable { self =>
    // 注册该监听器
    register()
    //订阅 openfile 消息
    on('openfile) {
        (event) =>
            {
                // 获取并读入文本
                val file = event.args.first.asInstanceOf[MdFile]
                file >> (this.text = _)
            }
     }
}

####主窗口 Frame:

<!-- lang: scala -->
val frame = new Frame with Listenable {
    title = "Marky"
    
    menuBar = new MenuBar with MenuDef {
        border = Swing.EmptyBorder(2, 3, 0, 3)
    }
    visible = true

    register()
    on('openfile, 'savefile) {
         (event) =>
              val file = event.args.first.asInstanceOf[MdFile]
              title = file.name + " - Marky"
      }
  }

最后是 MarkyEvent.scala ,大概有70行左右。 不过这 2B 编辑器要自己一行行缩进,我就不再这贴了=。 =

###Markdown2HTML

没啥好说的,一个多线程的 Actor(即非Swing调度器)做转换,一个模块负责订阅编辑区内容,发送并接受字符串,然后修改显示区内容。

###I18N 更没啥好说的了,只是为了不在代码中写中文而已。在这里个人也建议尽量不要在代码中写中文的好。


没了。不玩了。回去继续捣鼓 WEB。

© 著作权归作者所有

共有 人打赏支持
上一篇: done!?
下一篇: webColle
aiasfina
粉丝 33
博文 3
码字总数 1515
作品 0
深圳
程序员
私信 提问
加载中

评论(2)

aiasfina
aiasfina

引用来自“千叶”的评论

是我的菜

:)
千叶
千叶
是我的菜
机器学习算法 Java 库 Smile 1.5.0 发布,引入新特性

机器学习算法 Java 库 Smile 1.5.0 已发布。该版本引入了新特性和修复 bug,改进了对 Windows 的支持,具体如下: DataFrame New Shell for Mac and Linux Shell improvement for Windows Ou...

局长
2017/11/23
1K
4
在Google App Engine上创建你的Java/Scala项目

GAE(Google App Engine)是Google推出的服务器托管项目,目前支持Python、Java、Go(为什么没有传说中的G-SPOT?)三种语言。GAE的免费版本有很多限制,但是可是很稀有的可以托管Java项目的服...

戴威
2011/09/06
1K
3
杨博/stateless-future

Stateless Future is a set of DSL for asynchronous programming, in the pure functional favor. Usage import scala.concurrent.duration._import scala.util.control.Exception.Catcheri......

杨博
2014/04/19
0
0
Scala 2.8.0 Final 释出

经历了7个RC版本,Scala终于迎来了2.8.0的Final版本,这是修正了大量Bug和增强了若干特性的最终版本。 注意,相关的编辑器和IDE也要做相应的更新,如Scala IDE for Eclipse,目前已更新至2.8...

曾建凯
2010/07/15
670
0
老猪/ScalaConsole

ScalaConsole Reloaded (V2.0) ScalaConsole 是什么 ScalaConsole是Scala语言REPL的图形界面替代者。 为什么需要 ScalaConsole 命令行REPL的编辑功能有限,只能基于行来进行编辑,如果输入错...

老猪
2015/02/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

myeclipse 启动到10分之一左右就挂了

删掉 {workspace}/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi

夜醒者
11分钟前
0
0
Hive on Spark 伪分布式环境搭建过程记录

进入hive cli是,会有如下提示: Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) ......

PeakFang-BOK
18分钟前
0
0
用户输入和while 循环

# 用户输入和while循环# 7.1函数input() 的工作原理# 函数input() 让程序暂停运行,等待用户输入一些文本。获取用户输入后,Python将其存储在一个变量中,以方便你使用。message = inp...

吕湘颖
19分钟前
0
0
开发函数计算的正确姿势 —— 排查超时问题

写不尽的 code,查不完的 bug 通常我们写 bug,哦,不对,写代码时总不会一帆风顺,往往各种 bug 充斥其中,即使测试有较高的代码覆盖率往往也会有漏网之鱼。能写出一些比较隐蔽或者看起来像...

阿里云云栖社区
23分钟前
1
0
Python3新特性

一、类型注解 例子: def add(x:int, y:int) -> int: return x + y 解释: 类型`的形式指定函数的**参数类型**,用`-> 类型`的形式指定函数的**返回值类型 然后特别要强调的是,Pyt...

_Change_
38分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部