今天我們來講講用Scala實現Qt QWidget對象的Eventable接口
這個Eventable接口是我項目中常用的一個東西
Scala強調FP
但是Qt Jambi本身是基於OOP的
事件重載需要在類裡面進行
在前面展示的例子中
大家可以看到經常會這樣展開一個類去重載
new QLabel {
override def xxxxEvent } 這種聲明的方法多了其實很容易讓人覺得不規范
而且閱讀也是不易
所以我萌生了讓將js那種聲明事件風格的代碼加入至此
js是一個可以很fp的語言
而scala也是
這不是一個很好的決定嗎?獻上具體的代碼
package yourporject
package
import llection
mutable
{ ArrayBuffer
HashMap } import com
trolltech
qt
gui
_ import re
_ import re
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
md
=> 將字符串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)
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 eventType
Name(_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
_
event
_
)
def addEvents(events
Ev*)
this
type = {
events
foreach(this
addEvent(_))
this
}
// 判斷是否存在事件
def hasEvent(name
String)
Boolean = ntains(name
toEventName)
// Qt事件覆蓋
override def event(event
QEvent)
Boolean = {
eventType
Name(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(
雙擊了!
)
} )
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25803.html