今天我们来讲讲用Scala实现Qt QWidget对象的Eventable接口这个Eventable接口是我项目中常用的一个东西Scala强调FP但是Qt Jambi本身是基于OOP的事件重载需要在类里面进行在前面展示的例子中大家可以看到经常会这样展开一个类去重载 new QLabel { override def xxxxEvent } 这种声明的方法多了其实很容易让人觉得不规范而且阅读也是不易所以我萌生了让将js那种声明事件风格的代码加入至此js是一个可以很fp的语言而scala也是这不是一个很好的决定吗?献上具体的代码 package yourporjectpackage import llectionmutable{ ArrayBuffer HashMap } import comtrolltechqtgui_ import re_ import reQEvent import comtrolltechqtQSignalEmitter_ import comagiersmvcBase /* * Base类里面封装了的是对于Java和Scala既有类的方法扩展使用的是隐式混入的方式不会改变对象本身 * 如 * onClicktoEventName => click * 中文字encode => url encode * 繁体字encodeSys => 这个是根据客户端操作系统默认的字符编码进行urlencode * 繁体字toSimplified => 繁体转简体 * 简体字toTraditional => 简体转繁体 * hello_worldtoCamelCase => HelloWorld * good guysdump(temptxt) => 将字符串内容输入到一个io文件中 * hello worldmd => 将字符串md加密 */ 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) thistype = { fns += fn this } def fire(widget T event QEvent) EventHandle = { val handle = EventHandle(widget event) fnsforeach(_(handle)) handle } } // 定义Qt标准时间类型转换到当前类的助记名 // name统一使用小写 // @TODO 要不断增加QEventType的内容 private val _eventsMap = HashMap[QEventType String]( QEventTypeShow > show QEventTypeMouseButtonPress > click QEventTypeMouseButtonDblClick > doubleclick QEventTypeFocusIn > focus QEventTypeFocusOut > blur QEventTypeEnter > enter QEventTypeLeave > leave ) // 事件 private val _events = HashMap[String FnContainer]() // 传入Qt的QEventType获取其在Eventable内部的快捷助记名 def eventTypeName(_type QEventType) Option[String] = _eventsMapget(_type) // 装载事件 // waddEvent(show handle => { /* */ }) def addEvent(s String fn Fn) thistype = { val name = stoEventName if (!thishasEvent(name)) _events(name) = FnContainer(fn) else _events(name) + fn this } // waddEvent(click > { handle => println(handleevent) }) def addEvent(event Ev) thisthistype = thisaddEvent(event_ event_) def addEvents(events Ev*) thistype = { eventsforeach(thisaddEvent(_)) this } // 判断是否存在事件 def hasEvent(name String) Boolean = ntains(nametoEventName) // Qt事件覆盖 override def event(event QEvent) Boolean = { eventTypeName(event`type`()) match { case Some(name) => if (thishasEvent(name)) { val handle = _events(name)fire(thisasInstanceOf[T] event) } case _ => } superevent(event) } } 这个Eventable只是一个很初步的封装只是针对所有的QWidget适用我还有好些想法比如延时事件激活定时事件循环并且希望能对QObject进行全部的适用而对于Qt的信号槽自然也要兼容唉想法太多可惜时间太有限先用着吧能好像写js一样写事件声明该知足了 下面奉上使用的代码 class Widget extends QWidget with Eventable[QWidget] val w = new Widget() waddEvent(onClick handle => { println(单击了!) }) waddEvents( show > { handle => println(窗口显示了) } doubleClick > { handle => println(双击了!) } ) |