a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 319|回复: 0

[专业语言] Java认证:QWidget对象的Eventable接口

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证:QWidget对象的Eventable接口
* e& L0 C0 a' y: S! P2 ^- m* o- s今天我们来讲讲用Scala实现Qt QWidget对象的Eventable接口。这个Eventable接口是我项目中常用的一个东西,Scala强调FP,但是Qt Jambi本身是基于OOP的,事件重载需要在类里面进行。在前面展示的例子中,大家可以看到经常会这样展开一个类去重载:
4 y; \/ m1 E) G* l1 Znew QLabel {
; w$ t( ~5 j3 ], }: {override def xxxxEvent } 这种声明的方法多了其实很容易让人觉得不规范,而且阅读也是不易。所以我萌生了让将js那种声明事件风格的代码加入至此,js是一个可以很fp的语言,而scala也是,这不是一个很好的决定吗?献上具体的代码:- R& s3 f8 L5 v9 l" S
package yourporject.package
& ^: ^8 x0 O" B7 t* yimport 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 /*6 C# N. V* `" ]: k- K7 ]  z; D/ X
* Base类里面封装了的是对于Java和Scala既有类的方法扩展,使用的是隐式混入的方式,不会改变对象本身。& d) x# z: ]( L  u: j% p5 \+ F% N- J
* 如0 @( F+ W. G0 H# N1 x" E
* “onClick”.toEventName =》 click- \7 v  X& U# [3 x9 ~# w
* “中文字”.encode =》 url encode
5 u# Q4 [4 M$ |. L: J: d* “繁体字”.encodeSys =》 这个是根据客户端操作系统默认的字符编码进行urlencode- s- B8 c& T9 h3 u
* “繁体字”.toSimplified =》 繁体转简体' D) |9 t$ u; G7 K
* “简体字”.toTraditional =》 简体转繁体
8 u/ n/ L$ F2 V7 D* ?. g* “hello_world”.toCamelCase =》 HelloWorld/ l/ E$ V6 r( g: ]9 g: N
* “good guys”.dump(“temp.txt”) =》 将字符串内容输入到一个io文件中0 ^, t; n/ T; n( F4 z! b8 y$ D
* “hello world”.md5 =》 将字符串md5加密
- `+ _$ ], g; z9 ?' I; q  W- g3 E3 C7 }*/* r0 S& s- ?7 W) r6 I* Q* i/ E7 u
trait Eventable[T 《: QWidget] extends QWidget with Base {
4 L$ a/ z4 W3 ?" D// 定义闭包的格式声明4 T: Y/ C5 _4 b% V9 Z4 O: c" x
// 凡是在Eventable里使用闭包的类型,应该首先使用Fn类型
2 E! Z8 L# z. p2 y: j! I8 g// 修改闭包类型,应该在此修改,而不在具体声明的地方修改% Y& \& j+ w" l
type Fn = EventHandle =》 Unit! X' s, z9 e2 p- K
// 定义一个event的类型组合
) Y  N( {( X/ c7 D# k( u$ v// 这个代表的实际上是String -》 Fn或者(String, Fn)9 q" n9 B- C5 T) d3 f. Q' j6 R
type Ev = (String, Fn)! J+ X8 {' _/ d5 i  f/ b8 g2 p
/**
% N3 t1 l  o$ [: f- H* 事件接管对象) a1 h5 E$ s0 c" o
* 用于接管声明事件时的闭包处理,并临时寄存该闭包中的各种状态和变量
  O3 N0 Z& Y$ M# j+ ~# X* @TODO 要逐渐增加他的寄存和读取的接口2 t( ?6 D3 j. u
* @author Janpoem
: A  T4 v% Z3 x  L*/" {$ a1 c- p: x- ]# \+ b. w7 y* O
sealed case class EventHandle(val widget : T, val event : QEvent) {# H, W  m8 p! K6 O/ V- f$ M
// 这个是用来获取该widget执行event时的状态的
$ A; W. z* H& N7 t. _' Eprivate var _break = false
7 V% X0 R* S, F; \* O7 B// 以下) Q+ E- B. j: C; f" ~- w( M
def isBreak = _break; Q* D, W' N, ~! J1 {
def isBreak_=(is : Boolean) = _break = is6 u& K1 \- |6 ^
def break(fn : EventHandle =》 Boolean) = isBreak = fn(this)9 T6 }3 T, d5 `" l( n! _
}; j9 N1 U  E! b7 K" b( _6 V5 t

& H9 Z7 J2 `' N+ D# Q: L/ v  m+ M( \: G! `; B+ }# [. k
/**& Q0 N. I- V+ m9 r! p$ Z
* 闭包的存放容器
% ^# r9 Y3 _; \( b8 ?7 B3 h* 允许将闭包作为一个队列存放,并在fire的时,按照队列先后顺序执行。7 c  L) @' n; B3 Q
* @author Janpoem" S) A- Q1 N( h" B8 U4 z: V' Q7 I0 o
*/
# T& Y4 J# x% Q+ u" _$ s. A8 X, Zsealed case class FnContainer(fn : Fn) {- J9 F% E$ x1 ~9 C, d2 k
private var fns = ArrayBuffer[Fn](fn)! E, F; Q9 V9 `; O$ M* ?7 Y
def +(fn : Fn) : this.type = {% Z$ ~4 N5 Z6 l( C
fns += fn) X& m+ L( W! G8 M* y) H
this( P# }. \1 _0 ^# c4 g# o. t
}
9 o0 g6 g& l! h/ ]) Qdef fire(widget : T, event : QEvent) : EventHandle = {, v: u' T6 \7 o5 ?# B$ V
val handle = EventHandle(widget, event)
2 w$ z/ B* D8 _1 p) l" U+ ]) E+ kfns.foreach(_(handle))
! b3 l0 g1 }! w) X3 bhandle
) b  q2 s2 U* B0 t}3 u0 O8 ?& W4 G" g8 j
}8 ~4 f! O% u. |# v  O
// 定义Qt标准时间类型转换到当前类的助记名
+ \8 `, h& z" g! z// name统一使用小写* N: q; y4 c2 b0 b- }
// @TODO 要不断增加QEvent.Type的内容
8 f6 v! g+ U" |! H6 _: q. b5 {private val _eventsMap = HashMap[QEvent.Type, String](
  c# d) K4 V- t  M0 [; l) o6 uQEvent.Type.Show
7 g; B. b; k) O/ U-》 “show”,
& t- f3 ~, \; ~- s( B9 EQEvent.Type.MouseButtonPress  ~" q% i6 c0 y+ ~7 `7 E8 ]
-》 “click”,6 Q2 g& v% l8 j! G' I3 _
QEvent.Type.MouseButtonDblClick -》 “doubleclick”,
6 s% }) a- r, U/ SQEvent.Type.FocusIn
' _8 z, v4 Q7 S-》 “focus”,
3 {, h( c8 ]8 oQEvent.Type.FocusOut) ?4 o3 q1 @$ ^: N
-》 “blur”,
8 O$ ~! n  X/ [QEvent.Type.Enter4 y' e3 y% x% @8 e) S' g
-》 “enter”,
" j" [5 F9 X, xQEvent.Type.Leave/ I# G( _# X* U4 v6 O6 T& q
-》 “leave”
1 \/ }& e# T# r: i& Y' h2 j; v; C9 U# q
// 事件
+ ?* `9 m9 v! F, m  B' n# }% B& pprivate val _events = HashMap[String, FnContainer]()
, ], q1 o' R( u3 ~; l* B// 传入Qt的QEvent.Type,获取其在Eventable内部的快捷助记名4 f% h! q7 J6 o/ M
def eventType2Name(_type : QEvent.Type) : Option[String] = _eventsMap.get(_type); X9 D/ z$ a$ m* v) m
// 装载事件
/ [, H* u6 o' }' b- k// w.addEvent(“show”, handle =》 { /* */ })
0 V$ w, e: x- w) m# s3 kdef addEvent(s : String, fn : Fn) : this.type = {% F) }7 x$ j4 x5 u5 T0 c3 l6 A+ B
val name = s.toEventName/ Z5 ~8 \0 B8 y7 n& P
if (!this.hasEvent(name))4 K2 u, e4 A& Z
_events(name) = FnContainer(fn)
2 w3 P. B1 s$ a" Y% ?7 k9 Celse# ?' V+ t0 J, s6 Y9 n! H$ s
_events(name) + fn
! `- j/ \: D  n8 N; V/ P  \this
+ O+ R2 K% L, w& h4 I}$ U4 z- m9 j( I' c4 E
// w.addEvent(“click” -》 { handle =》 println(handle.event) })7 I  P+ O3 S, ~' R% j! M  N5 k6 V
def addEvent(event : Ev) : thisthis.type = this.addEvent(event._1, event._2)
# S  e; [3 M: Y0 P! U+ r6 }+ Gdef addEvents(events : Ev*) : this.type = {) D) Y0 G9 u1 B
events.foreach(this.addEvent(_))1 \% _: F" R, k( o% x2 R2 ?; G
this
$ L- ^0 a# {  n& E}6 X; x- y1 A0 T" M% G! Q( L

& A2 e0 U! ^$ `0 f- {9 z% I; Z' ]
. R$ r5 R5 m. @; ]1 y8 i// 判断是否存在事件
; [6 X( V% Z1 U% _def hasEvent(name : String) : Boolean = _events.contains(name.toEventName)
, H* U0 u: G0 ^: D$ Z" [// Qt事件覆盖6 ], ?1 g6 b! y, `; @1 j( k/ [3 Z
override def event(event : QEvent) : Boolean = {
7 R% H6 J+ V; F+ T6 neventType2Name(event.`type`()) match {9 J: g- V$ k- y. k2 y& w( E
case Some(name) =》
9 M+ n+ N1 P) g; J2 u( sif (this.hasEvent(name)) {) r9 T0 ~% p( E( ~) Q) r
val handle = _events(name)。fire(this.asInstanceOf[T], event), Y/ c* Z6 f/ S  r8 ^! x
}  o& T$ d9 `- i: ^- T. A+ }. _, p
case _ =》7 V' J7 E  `% W% F  b
}
* g% y6 R, I+ o, ssuper.event(event)- c( P* j) ]/ i" p) M( k. G  z: V9 ~
}
$ @8 @- ~4 q  Q, @}; R* c" J0 M+ n  X9 H( o
这个Eventable只是一个很初步的封装,只是针对所有的QWidget适用,我还有好些想法,比如延时事件激活,定时事件循环。并且希望能对QObject进行全部的适用,而对于Qt的信号槽,自然也要兼容。唉,想法太多,可惜时间太有限。先用着吧,能好像写js一样写事件声明,该知足了。
8 A# W$ a# T" D0 S- A下面奉上使用的代码:
/ `5 L7 f. D9 c$ k' S# aclass Widget extends QWidget with Eventable[QWidget], W5 w- i- F0 N
val w = new Widget() w.addEvent(“onClick”, handle =》 {1 [  g$ T% h+ N; k
println(“单击了!”) }) w.addEvents(
7 I/ h9 N" N+ W1 O, g3 H“show” -》 { handle =》
4 y$ M- j9 w% ?) d" J6 P7 ]. _; Mprintln(“窗口显示了”)
' V6 u2 g$ w+ `: C},1 \9 Q* _" b+ y+ J4 v, {! \; S
“doubleClick” -》 { handle =》2 e& P& L3 t/ _3 n
println(“双击了!”)% b$ X. M- v8 y/ ~5 k! D
} )
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-3-29 15:31 , Processed in 0.243008 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表