a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 384|回复: 0

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

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证:QWidget对象的Eventable接口
! `% `4 O& k' w4 x今天我们来讲讲用Scala实现Qt QWidget对象的Eventable接口。这个Eventable接口是我项目中常用的一个东西,Scala强调FP,但是Qt Jambi本身是基于OOP的,事件重载需要在类里面进行。在前面展示的例子中,大家可以看到经常会这样展开一个类去重载:8 D/ B, I: M5 A; V2 R
new QLabel {
, k! x, G5 l8 J$ U' N. R) G. J  ?* g! Soverride def xxxxEvent } 这种声明的方法多了其实很容易让人觉得不规范,而且阅读也是不易。所以我萌生了让将js那种声明事件风格的代码加入至此,js是一个可以很fp的语言,而scala也是,这不是一个很好的决定吗?献上具体的代码:; ?, t7 ]/ y( Z
package yourporject.package
' G2 V' c" D2 o& Vimport 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 /*
; Y+ T8 f2 q. v" E0 Z! ~* Base类里面封装了的是对于Java和Scala既有类的方法扩展,使用的是隐式混入的方式,不会改变对象本身。) D# v& t5 v0 P
* 如
0 N3 b4 j1 x2 f) `* “onClick”.toEventName =》 click
. v5 i6 e+ _: T2 B* f2 A% m& R* “中文字”.encode =》 url encode
" C4 l. V. t3 r' I  R2 L+ ~  c* “繁体字”.encodeSys =》 这个是根据客户端操作系统默认的字符编码进行urlencode
) H( w5 `( H  g; S5 |  }+ f* “繁体字”.toSimplified =》 繁体转简体5 @7 l/ N' w9 A
* “简体字”.toTraditional =》 简体转繁体
! s. w: d$ ~2 Q, g7 }* “hello_world”.toCamelCase =》 HelloWorld
0 G  d& w5 M. q# C6 ^, k* “good guys”.dump(“temp.txt”) =》 将字符串内容输入到一个io文件中8 L$ K$ K3 _( V  m1 m% }* P
* “hello world”.md5 =》 将字符串md5加密$ [" N/ E9 I5 {* y
*/
. ?1 Z3 w8 g- g# Q; c' q; Utrait Eventable[T 《: QWidget] extends QWidget with Base {
7 a; _* N# k2 G3 j! g( u6 a7 u8 u( l// 定义闭包的格式声明0 d& p3 k0 V' {3 k- {' }8 o
// 凡是在Eventable里使用闭包的类型,应该首先使用Fn类型! z' _" r/ P; U
// 修改闭包类型,应该在此修改,而不在具体声明的地方修改
0 m5 `: W+ |. H6 s' n/ ^# wtype Fn = EventHandle =》 Unit; H& e8 V, u8 r8 l1 I/ ^. @6 r
// 定义一个event的类型组合
  T- b" p" M: a" R8 @$ d7 W// 这个代表的实际上是String -》 Fn或者(String, Fn)
% u4 i- b" ~* L0 m. ]4 ptype Ev = (String, Fn)& O! z' s* O+ ^7 |/ z" n$ d
/**
8 ]7 N, f' G# B- D; B* z* 事件接管对象8 u" o; t4 e9 \! s
* 用于接管声明事件时的闭包处理,并临时寄存该闭包中的各种状态和变量: N. j' e' [2 A; k
* @TODO 要逐渐增加他的寄存和读取的接口
, @1 O' v7 l% b: |  i* @author Janpoem0 e2 w2 k* l6 Q4 y+ ~( I6 ~
*/& x& x" m) Y; e3 R" v
sealed case class EventHandle(val widget : T, val event : QEvent) {
8 Z9 J/ e) C1 A6 s1 A7 Z7 O" D4 _// 这个是用来获取该widget执行event时的状态的
% j4 i. R4 [% @$ _7 f7 B& m# @, Rprivate var _break = false0 l4 \- [/ H. b& u4 @/ |  M
// 以下
0 o* q) _3 L, m2 q  V, r; |2 [; udef isBreak = _break
3 q# [8 l+ X0 X* |. Bdef isBreak_=(is : Boolean) = _break = is
- B0 ?& t6 }4 @( M3 Idef break(fn : EventHandle =》 Boolean) = isBreak = fn(this)
! K+ V# |) h, s  m) K}- O$ e, q/ [6 Y4 P3 _

8 H: K- G6 Q1 h  E" r, J2 S# P" F4 C, C4 t
/**
; e6 B3 |$ o" q" f) ]! j* 闭包的存放容器
' u6 ^# n* F* i4 Z% ~* 允许将闭包作为一个队列存放,并在fire的时,按照队列先后顺序执行。
& v9 m, U& J/ ?% P' V8 L& g& p$ d* @author Janpoem: W5 Y; v- @1 s, f: l7 @
*/
6 s% D  l6 v$ ^5 M* V1 usealed case class FnContainer(fn : Fn) {
% r" X! F- ^& F, r1 y- V/ Xprivate var fns = ArrayBuffer[Fn](fn)
3 F- e2 Q" u/ U6 w, i+ z# vdef +(fn : Fn) : this.type = {3 e2 X/ h$ e. B) @
fns += fn7 @/ g  _) B( e
this
' l0 S8 H- x5 [; \/ W" `}
% K5 X1 H* P" Z' d. @: fdef fire(widget : T, event : QEvent) : EventHandle = {
- l, k( [/ u; `0 p6 Q) k4 Wval handle = EventHandle(widget, event)$ A. {$ L+ d1 `7 [. W
fns.foreach(_(handle))/ C3 j; L; }  C5 z3 Y
handle
9 @6 i7 x) F, W9 j$ p& V9 {+ L! M' }7 K}* n: r' T. E# x3 K( y  H
}% C+ @3 Q% }6 d( l0 L' N3 r
// 定义Qt标准时间类型转换到当前类的助记名+ p, C5 I' W/ _% K
// name统一使用小写
$ K  [- L$ F$ K) x// @TODO 要不断增加QEvent.Type的内容
6 r) N$ Y+ ]7 _9 O2 _private val _eventsMap = HashMap[QEvent.Type, String](6 {+ z/ i6 ?- Z& ^9 f# K
QEvent.Type.Show; t# c& D$ i5 O2 h% R) s
-》 “show”,9 ]$ f0 n: _2 B6 W/ H6 y$ [; @
QEvent.Type.MouseButtonPress1 M$ \0 W4 D8 r2 y9 A: o4 ]
-》 “click”,$ U- z& t, t) j/ [$ x
QEvent.Type.MouseButtonDblClick -》 “doubleclick”,; e) f9 ^8 `. c/ ^* F
QEvent.Type.FocusIn' F: J- U( C8 a( K
-》 “focus”,
: |1 J  p! n; T, A) K$ Y, M$ [5 v" s/ mQEvent.Type.FocusOut- Z7 S% I# H" [5 F; S
-》 “blur”,; N8 C' K+ T1 k7 c6 a, a
QEvent.Type.Enter
4 o- V2 y) v1 U-》 “enter”,
4 G- ?( b+ n* N: uQEvent.Type.Leave
! s. {6 b7 B: C6 L* ^-》 “leave”
. X/ m: |4 r) @& Y0 B
$ X/ \! v( E3 G3 D4 u// 事件
3 f# X$ @! C# m8 x6 m9 sprivate val _events = HashMap[String, FnContainer]()) O2 {- a  M. f9 Z) X( K
// 传入Qt的QEvent.Type,获取其在Eventable内部的快捷助记名
4 C# P7 f9 @: ^5 S$ Z: ]6 A1 L0 [) Edef eventType2Name(_type : QEvent.Type) : Option[String] = _eventsMap.get(_type)$ i" x1 l/ c" Y; |# P8 u9 }5 Y/ M
// 装载事件
7 j. y1 I2 l3 b5 N1 `9 q// w.addEvent(“show”, handle =》 { /* */ })
7 _4 C% h' B' J4 vdef addEvent(s : String, fn : Fn) : this.type = {& e% y* t8 ?8 _9 ?( G
val name = s.toEventName
+ u) h( i! F/ w& f# D* q( Aif (!this.hasEvent(name))
- }# y% c; K" ^$ R1 o' O. M_events(name) = FnContainer(fn): b3 h& o/ o& Y7 Y) K' V2 ~! {
else1 F( U: _0 l' n% z: c7 e+ C% w- U7 O
_events(name) + fn4 ?* o& _5 h/ B+ K2 O2 P+ s& }% J, V1 ?
this
2 W# p2 o& X+ Y7 j* [8 i% m1 V% y}' d2 p7 |. f9 K. B
// w.addEvent(“click” -》 { handle =》 println(handle.event) })
; ^. s1 t$ x1 Y( X" Edef addEvent(event : Ev) : thisthis.type = this.addEvent(event._1, event._2)
) w: i2 E+ n/ M- u* K& e& W+ x2 pdef addEvents(events : Ev*) : this.type = {
5 |- D% O; g8 H4 {( G" h# q0 Y. \events.foreach(this.addEvent(_))2 {# c6 V; [/ y2 U$ U: L
this
4 d4 U% P/ C, T% Y# \* o}! w2 m8 C8 u8 z" m

* N# _, a) `# B6 w6 T# b6 ~
( }3 {! j6 D( n// 判断是否存在事件
2 j5 i3 m# J0 I; o7 F, [7 _. Q5 sdef hasEvent(name : String) : Boolean = _events.contains(name.toEventName)
# t& s$ |! v2 M7 r// Qt事件覆盖
' C' V" x3 _1 {override def event(event : QEvent) : Boolean = {- z! f7 q1 n; x; h
eventType2Name(event.`type`()) match {2 p' S* o- A3 q# }; m
case Some(name) =》
1 h* S& h! k7 {" A+ |* B) B- Sif (this.hasEvent(name)) {
# |2 X. W. {, |val handle = _events(name)。fire(this.asInstanceOf[T], event), u9 `. V! S4 U3 @# O" o
}( b& n, i, ^) I* x
case _ =》$ Z6 S. M3 d0 ]& v8 j; i
}
' D" ]% o7 n: J, b# d, ysuper.event(event)
( l" F0 A7 Q3 {% }) I& y}( Y# G: B+ K8 _% ^4 j
}1 h/ \# @; h9 |
这个Eventable只是一个很初步的封装,只是针对所有的QWidget适用,我还有好些想法,比如延时事件激活,定时事件循环。并且希望能对QObject进行全部的适用,而对于Qt的信号槽,自然也要兼容。唉,想法太多,可惜时间太有限。先用着吧,能好像写js一样写事件声明,该知足了。$ E% j$ E7 _& O6 ~
下面奉上使用的代码:
) w% y1 D8 b/ vclass Widget extends QWidget with Eventable[QWidget]: Q2 O: j9 f  s5 `3 v
val w = new Widget() w.addEvent(“onClick”, handle =》 {
- D; b3 `8 h( e( e& o# eprintln(“单击了!”) }) w.addEvents(1 r3 O) _( o# R4 r4 |
“show” -》 { handle =》+ c, O8 {9 I5 @' l
println(“窗口显示了”)0 B# `3 C# J% d; w
},3 ~& L8 u- e5 }) Z
“doubleClick” -》 { handle =》7 E$ e2 d2 @& Y  z* P* z1 _( {' J8 s
println(“双击了!”)3 Y3 b9 j$ V/ L6 x% y1 K& f0 w9 Q
} )
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-27 19:46 , Processed in 0.561592 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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