详解 Qt QWidget对象的Eventable接口 (Scala实现)

移动开发
本文介绍的是详解 Qt QWidget对象的Eventable接口(Scala实现),对于Scala,本文又介绍,先来看内容。

Qt QWidget对象的Eventable接口(Scala实现)是本文将要介绍的内容,Scala编程语言近来抓住了很多开发者的眼球。如果你粗略浏览Scala的网站,你会觉得Scala是一种纯粹的面向对象编程语言,而又无缝地结合了命令式和函数式的编程风格。

这个Eventable接口是我项目中常用的一个东西,scala强调FP,但是Qt Jambi本身是基于OOP的,事件重载需要在类里面进行。

在这个例子中,( http://my.oschina.net/janpoem/blog/7017 )大家可以看到经常会这样展开一个类去重载:

  1. new QLabel {  
  2.   override def xxxxEvent  

这种声明的方法多了其实很容易让人觉得不规范,而且阅读也是不易。所以我萌生了让将js那种声明事件风格的代码加入至此,js是一个可以很fp的语言,而scala也是,这不是一个很好的决定吗?献上具体的代码:

  1. package yourporject.package  
  2. import scala.collection.mutable.{ ArrayBuffer, HashMap }  
  3. import com.trolltech.qt.gui._  
  4. import com.trolltech.qt.core._  
  5. import com.trolltech.qt.core.QEvent  
  6. import com.trolltech.qt.QSignalEmitter._  
  7. import com.agiers.mvc.Base  
  8. /*  
  9.  * Base类里面封装了的是对于Java和Scala既有类的方法扩展,使用的是隐式混入的方式,不会改变对象本身。  
  10.  * 如  
  11.  * "onClick".toEventName => click  
  12.  * "中文字".encode => url encode  
  13.  * "繁體字".encodeSys => 這個是根據客戶端操作系統默認的字符編碼進行urlencode  
  14.  * "繁體字".toSimplified => 繁體轉簡體  
  15.  * "简体字".toTraditional => 简体转繁体  
  16.  * "hello_world".toCamelCase => HelloWorld  
  17.  * "good guys".dump("temp.txt") => 将字符串内容输入到一个io文件中  
  18.  * "hello world".md5 => 将字符串md5加密  
  19.  */  
  20. trait Eventable[T <: QWidget] extends QWidget with Base {  
  21.   // 定义闭包的格式声明  
  22.   // 凡是在Eventable里使用闭包的类型,应该首先使用Fn类型  
  23.   // 修改闭包类型,应该在此修改,而不在具体声明的地方修改  
  24.   type Fn = EventHandle => Unit  
  25.   // 定义一个event的类型组合  
  26.   // 这个代表的实际上是String -> Fn或者(String, Fn)  
  27.   type Ev = (String, Fn)  
  28.   /**  
  29.    * 事件接管对象  
  30.    * 用于接管声明事件时的闭包处理,并临时寄存该闭包中的各种状态和变量  
  31.    * @TODO 要逐渐增加他的寄存和读取的接口  
  32.    * @author Janpoem  
  33.    */  
  34.   sealed case class EventHandle(val widget : T, val event : QEvent) {  
  35.     // 这个是用来获取该widget执行event时的状态的  
  36.     private var _break = false 
  37.     // 以下  
  38.     def isBreak = _break 
  39.     def isBreak_=(is : Boolean) = _break = is 
  40.     def break(fn : EventHandle => Boolean) = isBreak = fn(this)  
  41.   }  
  42.   /**  
  43.    * 闭包的存放容器  
  44.    * 允许将闭包作为一个队列存放,并在fire的时,按照队列先后顺序执行。  
  45.    * @author Janpoem  
  46.    */  
  47.   sealed case class FnContainer(fn : Fn) {  
  48.       
  49.     private var fns = ArrayBuffer[Fn](fn)  
  50.       
  51.     def +(fn : Fn) : this.type = {  
  52.       fns += fn  
  53.       this  
  54.     }  
  55.       
  56.     def fire(widget : T, event : QEvent) : EventHandle = {  
  57.       val handle = EventHandle(widget, event)  
  58.       fns.foreach(_(handle))  
  59.       handle  
  60.     }  
  61.   }  
  62.   // 定义Qt标准时间类型转换到当前类的助记名  
  63.   // name统一使用小写  
  64.   // @TODO 要不断增加QEvent.Type的内容  
  65.   private val _eventsMap = HashMap[QEvent.Type, String](  
  66.     QEvent.Type.Show                -> "show",  
  67.     QEvent.Type.MouseButtonPress    -> "click",  
  68.     QEvent.Type.MouseButtonDblClick -> "doubleclick",  
  69.     QEvent.Type.FocusIn             -> "focus",  
  70.     QEvent.Type.FocusOut            -> "blur",  
  71.     QEvent.Type.Enter               -> "enter",  
  72.     QEvent.Type.Leave               -> "leave"  
  73.   )  
  74.   // 事件  
  75.   private val _events = HashMap[String, FnContainer]()  
  76.  
  77.   // 传入Qt的QEvent.Type,获取其在Eventable内部的快捷助记名  
  78.   def eventType2Name(_type : QEvent.Type) : Option[String] = _eventsMap.get(_type)  
  79.   // 装载事件  
  80.   // w.addEvent("show", handle => { /*  */ })  
  81.   def addEvent(s : String, fn : Fn) : this.type = {  
  82.     val name = s.toEventName  
  83.     if (!this.hasEvent(name))  
  84.       _events(name) = FnContainer(fn)  
  85.     else  
  86.       _events(name) + fn  
  87.     this  
  88.   }  
  89.   // w.addEvent("click" -> { handle => println(handle.event) })  
  90.   def addEvent(event : Ev) : thisthis.type = this.addEvent(event._1, event._2)  
  91.     
  92.   def addEvents(events : Ev*) : this.type = {  
  93.     events.foreach(this.addEvent(_))  
  94.     this  
  95.   }  
  96.   // 判断是否存在事件  
  97.   def hasEvent(name : String) : Boolean = _events.contains(name.toEventName)  
  98.   // Qt事件覆盖  
  99.   override def event(event : QEvent) : Boolean = {  
  100.     eventType2Name(event.`type`()) match {  
  101.       case Some(name) => 
  102.         if (this.hasEvent(name)) {  
  103.           val handle = _events(name).fire(this.asInstanceOf[T], event)  
  104.         }  
  105.       case _ => 
  106.     }  
  107.     super.event(event)  
  108.   }  

这个Eventable只是一个很初步的封装,只是针对所有的QWidget适用,我还有好些想法,比如延时事件激活,定时事件循环。并且希望能对QObject进行全部的适用,而对于Qt的信号槽,自然也要兼容。唉,想法太多,可惜时间太有限。先用着吧,能好像写js一样写事件声明,该知足了。

下面奉上使用的代码:

  1. class Widget extends QWidget with Eventable[QWidget]  
  2.  
  3. val w = new Widget()  
  4. w.addEvent("onClick", handle => {  
  5.   println("单击了!")  
  6. })  
  7. w.addEvents(  
  8.   "show" -> { handle => 
  9.     println("窗口显示了")  
  10.   },  
  11.   "doubleClick" -> { handle => 
  12.     println("双击了!")  
  13.   }  

小结:详解 Qt QWidget对象的Eventable接口(Scala实现)的内容介绍完了,希望本文对你有帮助,更毒内容请参考编辑推荐!

【编辑推荐】

  1. Scala编程指南:面向对象编程
  2. Scala编程指南 揭示Scala的本质
  3. Scala编程指南 更少的字更多的事
  4. 新手必学 Qt 类简介之Qt QWidget 类
  5. QWidget QMainWindow QDialog 三者区别
责任编辑:zhaolei 来源: 互联网
相关推荐

2011-03-18 19:37:38

Eventable接口QtWidget

2011-07-04 16:12:00

QT QWidget

2011-06-24 10:05:51

QT 对象 父对象

2011-06-16 11:13:13

QtQWidget

2011-03-18 19:50:32

ScalaJVMQt

2011-06-23 13:38:27

QT 元对象 信号

2010-03-22 13:15:07

Python支付接口

2009-07-21 12:18:37

ScalaRational对象toString

2009-07-21 08:21:46

Scala对象相等性

2011-06-30 09:46:01

QT 显示视频 linux

2011-06-28 15:18:45

Qt 单例模式

2009-09-09 14:09:35

Scala Trait

2009-07-22 09:22:20

Scala工厂对象

2009-08-31 16:23:13

C#接口

2011-09-01 14:04:45

QT Webkit插件

2011-06-24 13:27:13

Ubuntu QT SDK

2019-05-14 09:05:16

SerializablJava对象

2009-09-09 11:14:16

Scala对象

2009-08-13 10:35:05

Scala数组排序

2010-03-11 10:34:22

Scala
点赞
收藏

51CTO技术栈公众号