文档章节

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

aiasfina
 aiasfina
发布于 2012/12/28 09:54
字数 1136
阅读 685
收藏 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。

© 著作权归作者所有

上一篇: webColle
下一篇: webColle
aiasfina
粉丝 33
博文 3
码字总数 1515
作品 0
深圳
程序员
私信 提问
加载中

评论(2)

aiasfina
aiasfina 博主

引用来自“千叶”的评论

是我的菜

:)
千叶
千叶
是我的菜
风一样的男人,谜一样的代码,C++11 lambda表达式

前言 C++11引入了lambda表达式,使得程序员可以定义匿名函数,该函数是一次性执行的,既方便了编程,又能防止别人的访问。 认识lambda表达式 这里假设我们定义了一个如上图的lambda表达式。现...

这个人很懒什么都没留下
2019/03/25
0
0
windows编程四大常用代码,恶意软件常用最后两点

Hello Boy 今天和大家讲讲,在做windows编程常用的三个短小代码。对于平时没用过这些代码的人,或许你可以考虑试着去看看在实践中能否用的上这些代码来处理实际问题或者实际需求。 First:透...

这个人很懒什么都没留下
2019/03/21
0
0
机器学习算法 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
1.9K
4
冒泡排序都会吧!那链表的冒泡排序?算法设计之单链表的冒泡排序

前言 大家在做学生成绩管理系统的时候,其中一个功能是要实现对学生的成绩从高到低排名,如果数据是存储在数组中的话,会很容易实现,但是这时成绩信息作为结构体成员被保存在单链表中,所以...

这个人很懒什么都没留下
2019/03/18
0
0
玩扑克牌中插扑克牌手法就是不一样,C语言经典算法之插入排序

插入排序 插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。当然,如果你说你打扑克牌摸牌的时候从来不...

这个人很懒什么都没留下
2019/04/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

golangWeb框架---github.com/gin-gonic/gin学习四(模型绑定、自定义校验、ShouldBindXXX、BindXXX)

文章目录 模型绑定、校验 绑定json(ShouldBindJSON) 绑定xml(ShouldBindXML)、form(ShouldBind) 自定义校验器(demo有问题) BindQuery\ShouldBindQuery(只限查询参数) BindJson(json)、Bind(...

osc_sju4uxml
15分钟前
13
0
golangWeb框架---github.com/gin-gonic/gin学习八(监听多端口、多类型的struct模型绑定)

文章目录 监听多端口 自定义的struct绑定form-data 监听多端口 如何利用gin实现监听多端口 package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/......

osc_04b0bwu2
17分钟前
8
0
golangWeb框架---github.com/gin-gonic/gin学习三(路由多视图函数、中间件、log日志)

文章目录 gin.New 路由包含多个HandlerFunc函数 使用中间件 如何写log日志 gin.New 我们之前的例子都是利用了gin.Default(),那么gin.New()跟它有什么区别?来简单看下源码 gin.Default()源码...

osc_3361hjxk
18分钟前
11
0
golangWeb框架---github.com/gin-gonic/gin学习一(路由、多级路由、参数传递几种形式)

文章目录 Gin介绍 安装 快速开始 路径参数 构造参数 post传参 get+post混合形式 构造Map格式 分组路由 Gin介绍 Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布...

osc_0boqdoe2
19分钟前
16
0
golangWeb框架---github.com/gin-gonic/gin学习七(重定向、中间件Goroutines、http自定义配置)

文章目录 重定向 服务器内部重定向 中间件 中间件内部的Goroutines HTTP自定义配置 重定向 package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.De......

osc_mgvk29y5
21分钟前
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部