会计考友 发表于 2012-8-4 12:44:44

Java认证:QWidget对象的Eventable接口

Java认证:QWidget对象的Eventable接口
今天我们来讲讲用Scala实现Qt QWidget对象的Eventable接口。这个Eventable接口是我项目中常用的一个东西,Scala强调FP,但是Qt Jambi本身是基于OOP的,事件重载需要在类里面进行。在前面展示的例子中,大家可以看到经常会这样展开一个类去重载:
new QLabel {
override def xxxxEvent } 这种声明的方法多了其实很容易让人觉得不规范,而且阅读也是不易。所以我萌生了让将js那种声明事件风格的代码加入至此,js是一个可以很fp的语言,而scala也是,这不是一个很好的决定吗?献上具体的代码:
package yourporject.package
import scala.collection.mutable.{ ArrayBuffer, HashMap } import com.trolltech.qt.gui._ import com.trolltech.qt.core._ import com.trolltech.qt.core.QEvent import com.trolltech.qt.QSignalEmitter._ import com.agiers.mvc.Base /*
* Base类里面封装了的是对于Java和Scala既有类的方法扩展,使用的是隐式混入的方式,不会改变对象本身。
* 如
* “onClick”.toEventName =》 click
* “中文字”.encode =》 url encode
* “繁体字”.encodeSys =》 这个是根据客户端操作系统默认的字符编码进行urlencode
* “繁体字”.toSimplified =》 繁体转简体
* “简体字”.toTraditional =》 简体转繁体
* “hello_world”.toCamelCase =》 HelloWorld
* “good guys”.dump(“temp.txt”) =》 将字符串内容输入到一个io文件中
* “hello world”.md5 =》 将字符串md5加密
*/
trait Eventable[T 《: QWidget] extends QWidget with Base {
// 定义闭包的格式声明
// 凡是在Eventable里使用闭包的类型,应该首先使用Fn类型
// 修改闭包类型,应该在此修改,而不在具体声明的地方修改
type Fn = EventHandle =》 Unit
// 定义一个event的类型组合
// 这个代表的实际上是String -》 Fn或者(String, Fn)
type Ev = (String, Fn)
/**
* 事件接管对象
* 用于接管声明事件时的闭包处理,并临时寄存该闭包中的各种状态和变量
* @TODO 要逐渐增加他的寄存和读取的接口
* @author Janpoem
*/
sealed case class EventHandle(val widget : T, val event : QEvent) {
// 这个是用来获取该widget执行event时的状态的
private var _break = false
// 以下
def isBreak = _break
def isBreak_=(is : Boolean) = _break = is
def break(fn : EventHandle =》 Boolean) = isBreak = fn(this)
}


/**
* 闭包的存放容器
* 允许将闭包作为一个队列存放,并在fire的时,按照队列先后顺序执行。
* @author Janpoem
*/
sealed case class FnContainer(fn : Fn) {
private var fns = ArrayBuffer[Fn](fn)
def +(fn : Fn) : this.type = {
fns += fn
this
}
def fire(widget : T, event : QEvent) : EventHandle = {
val handle = EventHandle(widget, event)
fns.foreach(_(handle))
handle
}
}
// 定义Qt标准时间类型转换到当前类的助记名
// name统一使用小写
// @TODO 要不断增加QEvent.Type的内容
private val _eventsMap = HashMap[QEvent.Type, String](
QEvent.Type.Show
-》 “show”,
QEvent.Type.MouseButtonPress
-》 “click”,
QEvent.Type.MouseButtonDblClick -》 “doubleclick”,
QEvent.Type.FocusIn
-》 “focus”,
QEvent.Type.FocusOut
-》 “blur”,
QEvent.Type.Enter
-》 “enter”,
QEvent.Type.Leave
-》 “leave”

// 事件
private val _events = HashMap[String, FnContainer]()
// 传入Qt的QEvent.Type,获取其在Eventable内部的快捷助记名
def eventType2Name(_type : QEvent.Type) : Option[String] = _eventsMap.get(_type)
// 装载事件
// w.addEvent(“show”, handle =》 { /* */ })
def addEvent(s : String, fn : Fn) : this.type = {
val name = s.toEventName
if (!this.hasEvent(name))
_events(name) = FnContainer(fn)
else
_events(name) + fn
this
}
// w.addEvent(“click” -》 { handle =》 println(handle.event) })
def addEvent(event : Ev) : thisthis.type = this.addEvent(event._1, event._2)
def addEvents(events : Ev*) : this.type = {
events.foreach(this.addEvent(_))
this
}


// 判断是否存在事件
def hasEvent(name : String) : Boolean = _events.contains(name.toEventName)
// Qt事件覆盖
override def event(event : QEvent) : Boolean = {
eventType2Name(event.`type`()) match {
case Some(name) =》
if (this.hasEvent(name)) {
val handle = _events(name)。fire(this.asInstanceOf[T], event)
}
case _ =》
}
super.event(event)
}
}
这个Eventable只是一个很初步的封装,只是针对所有的QWidget适用,我还有好些想法,比如延时事件激活,定时事件循环。并且希望能对QObject进行全部的适用,而对于Qt的信号槽,自然也要兼容。唉,想法太多,可惜时间太有限。先用着吧,能好像写js一样写事件声明,该知足了。
下面奉上使用的代码:
class Widget extends QWidget with Eventable[QWidget]
val w = new Widget() w.addEvent(“onClick”, handle =》 {
println(“单击了!”) }) w.addEvents(
“show” -》 { handle =》
println(“窗口显示了”)
},
“doubleClick” -》 { handle =》
println(“双击了!”)
} )
页: [1]
查看完整版本: Java认证:QWidget对象的Eventable接口