天天看點

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

在《Qt Quick 事件處理之信号與槽》中介紹了 QML 中如何使用内建類型的信号以及如何自定義信号,這次我們來看看如何處理滑鼠、鍵盤、定時器等事件。這些時間在處理時,通常是通過信号來完成的。

滑鼠事件處理

    桌面開發的話,難免要處理滑鼠事件……

變色矩形示例

    看一個簡單的處理滑鼠事件的例子,先看代碼(handle_mouse.qml):

[javascript]  view plain copy

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
  1. import QtQuick 2.0  
  2. import QtQuick.Controls 1.1  
  3. Rectangle {  
  4.     width: 320;  
  5.     height: 240;  
  6.     MouseArea {  
  7.         anchors.fill: parent;  
  8.         acceptedButtons: Qt.LeftButton | Qt.RightButton;  
  9.         onClicked: {  
  10.             if(mouse.button == Qt.RightButton){  
  11.                 Qt.quit();  
  12.             }  
  13.             else if(mouse.button == Qt.LeftButton){  
  14.                 color = Qt.rgba((mouse.x % 255) / 255.0 , (mouse.y % 255) / 255.0, 0.6, 1.0);  
  15.             }  
  16.         }  
  17.         onDoubleClicked: {  
  18.             color = "gray";  
  19.         }  
  20.     }  
  21. }  

    使用 "qmlscene handle_mouse.qml" 指令,可以看到運作效果。上面的代碼僅僅是繪制一個矩形,當滑鼠左鍵按下時改變矩形區域的顔色,滑鼠右鍵按下時退出應用。圖 1 是剛運作時的效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖1 handle_mouse.qml 初始運作效果

    圖 2 是點選滑鼠左鍵後的效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

             圖 2 滑鼠左鍵點選後的效果

    如果你點一下滑鼠右鍵,程式會退出。

    示例簡陋,但足以說明如何處理滑鼠事件,下面咱們慢慢來看。

MouseArea

    MouseArea 對象可以附加到一個 item 上供 item 處理滑鼠事件,它本身是一個不可見的 item 。在其内部,可以直接引用它所附着的對象的屬性和方法。你可以将 MouseArea 了解為它所附着的 item 的代理。

    MouseArea 有很多屬性, enabled 用來控制是否處理滑鼠事件,預設值是 true ,如果你設定為 false ,那麼它所代理的 item 就會無視滑鼠事件。 acceptedButtons 屬性設定接收拿些個滑鼠按鍵産生的事件(左鍵、右鍵、中鍵),示例代碼 "acceptedButtons: Qt.LeftButton | Qt.RightButton;" 表示處理滑鼠左鍵和右鍵。 

    作為一個 item , MouseArea 也擁有 anchors 屬性,你可以使用它來描述有效的滑鼠區域。示例代碼 "anchors.fill: parent;" 表示整個矩形區域都接受滑鼠事件。

    MouseArea 還有很多其他屬性,如 hoverEnabled , pressed 等等,請參考 Qt 幫助文檔。

    示例代碼中,在 MouseArea 對象内使用了 onClicked 和 onDoubleClicked 兩個信号處理器,他們對應 MouseArea 的 onClicked 和 onDoubleClicked 信号, MouseArea 還有很多其他的信号,如 onPressed / onReleased / onEntered / onExited / onPressAndHold 等等,從名字上就可以看到這些信号的含義。

    onClicked 信号的參數是 MouseEvent 類型,名為 mouse ,是以你可以在信号處理器中直接使用 mouse 來查詢滑鼠事件的詳情。比如哪個 button 按下,正如示例代碼中看到的那樣, MouseEvent 的 button 屬性儲存了被按下的滑鼠按鍵标記, x , y 屬性儲存滑鼠指針位置。還有一個比較重要的屬性 accepted ,如果你處理滑鼠事件後不想這個事件再往下傳遞,就置其值為 true 。

    onDoubleClicked 信号代表輕按兩下事件,其參數也是 MouseEvent 類型,示例中輕按兩下滑鼠,矩形顔色變為灰色。

    簡單的滑鼠事件處理就這些内容,根據你應用的需要,可能你還會處理 onPressed / onReleased / onEntered 等等信号,請參考 Qt 幫助。

鍵盤事件處理

    手機上你可能較少處理鍵盤事件(有一個例外,BACK 按鍵),但是電腦上你免不了要響應鍵盤。 

會動的文本執行個體

    先看示例代碼,handle_key.qml :

[javascript]  view plain copy

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
  1. import QtQuick 2.0  
  2. import QtQuick.Controls 1.1  
  3. Rectangle {  
  4.     width: 320;  
  5.     height: 480;  
  6.     color: "gray";  
  7.     focus: true;  
  8.     Keys.enabled: true;  
  9.     Keys.onEscapePressed: {  
  10.         Qt.quit();  
  11.     }  
  12.     Keys.forwardTo: [moveText, likeQt];  
  13.     Text {  
  14.         id: moveText;  
  15.         x: 20;  
  16.         y: 20;  
  17.         width: 200;  
  18.         height: 30;  
  19.         text: "Moving Text";  
  20.         color: "blue";  
  21.         //focus: true;  
  22.         font { bold: true; pixelSize: 24;}  
  23.         Keys.enabled: true;  
  24.         Keys.onPressed: {  
  25.             switch(event.key){  
  26.             case Qt.Key_Left:  
  27.                 x -= 10;  
  28.                 break;  
  29.             case Qt.Key_Right:  
  30.                 x += 10;  
  31.                 break;  
  32.             case Qt.Key_Down:  
  33.                 y += 10;  
  34.                 break;  
  35.             case Qt.Key_Up:  
  36.                 y -= 10;  
  37.                 break;  
  38.             default:  
  39.                 return;  
  40.             }  
  41.             event.accepted = true;  
  42.         }  
  43.     }  
  44.     CheckBox {  
  45.         id: likeQt;  
  46.         text: "Like Qt Quick";  
  47.         anchors.left: parent.left;  
  48.         anchors.leftMargin: 10;  
  49.         anchors.bottom: parent.bottom;  
  50.         anchors.bottomMargin: 10;  
  51.         z: 1;  
  52.     }  
  53. }  

    這個示例通過上下左右四個按鍵移動一個文本串,空格鍵選中複選框, Esc 鍵退出應用。圖 3 是初始運作效果圖:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖 3 handle_key 初始效果

    圖 4 是我按了幾次方向鍵,按了空格鍵後的效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖 4 移動文本,選中複選框

    下面解釋示例代碼,介紹如何使用 Keys 對象和信号處理器處理按鍵事件

Keys 與 信号處理器

    其實在 《Qt Quick 事件處理之信号與槽》、《Qt Quick 簡單教程》和 《QML 語言基礎》三篇文章中我們都有提到 Keys 對象,有的示例中也用到過,這裡呢,我們專門介紹一下,力求使大家對 Keys 及按鍵處理有個較為全面的了解。

    Keys 對象是 Qt Quick 提供的,專門供 Item 處理按鍵事件的對象。它定義了很多針對特定按鍵的信号,比如 onReturnPressed / onEscapePressed / onDownPressed / onDigit0Pressed / onBackPressed 等等;它還定義了更為普通的 onPressed 和 onReleased 信号,一般地,你可以使用這兩個信号來處理大部分按鍵(請對照 Qt C++ 中的 keyPressEvent 和 keyReleaseEvent 來了解),它們有一個名字是 event 的 KeyEvent 參數,包含了按鍵的詳細資訊。

    KeyEvent 代表一個按鍵事件,如果一個按鍵被處理, event.accepted 應該被設定為 true 以免它被繼續傳遞;要是你不設定它,那它可能會繼續傳遞給其他的 item ,出現一些奇奇怪怪的問題。

    Keys 有三個屬性。

    enabled 屬性控制是否處理按鍵。 

    forwardTo 屬性是清單類型,它表示傳遞按鍵事件給清單内的對象,如果某個對象 accept 了某個按鍵,那位列其後的對象就不會收到該按鍵事件。示例代碼 "Keys.forwardTo: [moveText, likeQt];" 表明轉發按鍵給 id 為 moveText 的 Text 對象和 id 為 likeQt 的 CheckBox 對象。 moveText 在前面,如果它消耗掉某個鍵, likeQt 就收不到了。你可以修改 Text 對象的 Keys.onPressed 附加信号處理器,在 case 清單中添加 Qt.Key_Space 看看效果。

    priority 屬性允許你設定 Keys 附加屬性的優先級,有兩種,在 Item 之前處理按鍵,這是預設行為,在 Item 之後處理按鍵。你可以對照着 Qt C++ 的 keyPressEvent() 函數來了解,如果你在派生類中重載了 keyPressEvent() 方法,那麼你可以在重載方法的一開始調用父類的 keyPressEvent() ,也可以在你處理完感興趣的事件後再調用父類的 keyPressEvent() 。這期間的邏輯關系也很簡單,假如 Keys 先處理按鍵,如它吃掉了某個鍵,它所依附的 Item 對象就收不到這個按鍵了;反之亦然。

    Qt Quick 提供的一些元素本身會處理按鍵,比如示例中的 CheckBox ,它響應空格鍵來選中或取消選中。而我們不需要給它附加 Keys 對象來再次處理按鍵事件。當然,如果你想改變它的按鍵響應邏輯,可以這麼做,在解釋 priority 屬性時已經提到這點。

    最後還有一點要說明的是,如果你想某個元素處理按鍵,需要把焦點給它,這通過 Item 的 focus 屬性來控制,置 true 即可。

    現在再來解釋下示例代碼。

    Rectangle 對象的附加信号處理器 Keys.onEscapePressed 調用 Qt.quit() 退出,小白很,不說了。

    Text 對象實作了 Keys.onPressed 附加信号處理器,使用 switch-case 語句,分揀 event 參數的 key 屬性。如果是上下左右四個鍵,就變更 Text 的位置,置 accepted 為 true ,聲明這幾個按鍵已名花有主找到歸宿;否則就直接傳回,給别人機會處理按鍵。你也看到了,正是因為這樣, CheckBox 才能拿到空格鍵來選中或取消複選框。

    示例中的 CheckBox 對象定義時,沒有專門處理按鍵,因為 Qt Quick 提供的實作已經處理了按鍵了。

    嗯嗯,貌似内容很少?走着,看定時器去。

定時器

    定時器的作用還要說嗎?好像有點兒啰嗦了呀。定時器麼,就是周期性觸發的一個事件,和平常用的鬧鐘差不多。你可以利用定時器來完成一些周期性的任務,比如檢查和伺服器的連接配接呆死了沒,比如備份使用者資料……

定時器對象介紹

    在 QML 中, Timer 代表定時器,使用起來也很簡單,響應其 onTriggered() 信号即可,它也就這麼一個有用的信号。另外它還有幾個屬性要說明一下, interval 指定定時周期,機關是毫秒,預設值是 1000 毫秒; repeat 設定定時器是周期性觸發還是一次性觸發,預設是一次性的(好像和 QTimer 不一樣嗳);running 屬性,設定為 true 定時器就開始工作,設定為 false 就歇菜,預設是 false ; triggeredOnStart 屬性,怎麼說呢, Qt 總是對我們這麼好都有點兒那啥不好意思了,這個屬性是考慮到有些同志的特殊需求,本來定時器啟動後要等待設定的間隔才觸發,如果你設定這個屬性為 true ,那定時器開始執行時立馬先觸發一次,預設值是 false 。

    Timer 還有 start() / stop() / restart() 三個方法可以調用,它們會影響 running 屬性,望文生義吧您。

    現在來看一個簡單的示例,倒計時。

倒計時程式

    世界杯倒計時按天算,山中一日世上千年,咱們這個示例用1秒頂它一天,倒數十秒,然後就開香槟慶祝下。

    看代碼(count_down.qml):

[javascript]  view plain copy

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器
  1. import QtQuick 2.0  
  2. import QtQuick.Controls 1.1  
  3. Rectangle {  
  4.     width: 320;  
  5.     height: 240;  
  6.     color: "gray";  
  7.     QtObject{  
  8.         id: attrs;  
  9.         property int counter;  
  10.         Component.onCompleted:{  
  11.             attrs.counter = 10;  
  12.         }  
  13.     }  
  14.     Text {  
  15.         id: countShow;  
  16.         anchors.centerIn: parent;  
  17.         color: "blue";  
  18.         font.pixelSize: 40;  
  19.     }  
  20.     Timer {  
  21.         id: countDown;  
  22.         interval: 1000;  
  23.         repeat: true;  
  24.         triggeredOnStart: true;  
  25.         onTriggered:{  
  26.             countShow.text = attrs.counter;  
  27.             attrs.counter -= 1;  
  28.             if(attrs.counter < 0)  
  29.             {  
  30.                 countDown.stop();  
  31.                 countShow.text = "Clap Now!";  
  32.             }  
  33.         }  
  34.     }  
  35.     Button {  
  36.         id: startButton;  
  37.         anchors.top: countShow.bottom;  
  38.         anchors.topMargin: 20;  
  39.         anchors.horizontalCenter: countShow.horizontalCenter;  
  40.         text: "Start";  
  41.         onClicked: {  
  42.             countDown.start();  
  43.         }  
  44.     }  
  45. }  

    我在界面上放了個 Text 對象,它下面放一按鈕。 Rectangle 對象内定義了一個 Timer 對象,預設不啟動。當使用者點選 "Start" 按鈕時啟動定時器。我還設定了定時器的 triggeredOnStart 屬性哦,周期是 1 秒。

    計數儲存在 QtObject 對象中, id 是 attrs ,在附加信号處理器 Component.onCompleted 中初始化 counter 屬性的值為 10 。而在 Timer 對象的 onTriggered 信号處理器中遞減 counter ,當 counter 為 0 時修改 Text 對象的文本為 "Clap Now!" 。

    喏,就這麼簡單。

    來看下效果。圖 5 是初始效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖 5 倒計時程式初始效果

    圖 6 是計時效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖 6 計時

    圖 7 是倒計時結束的效果:

Qt Quick事件處理之滑鼠、鍵盤、定時器 滑鼠事件處理 鍵盤事件處理 定時器

            圖 7 倒計時結束

    如果你使用 qmlscene 運作 countdown.qml 文檔,可能會發現它有一個 BUG 哦, "Start" 按鈕第一次點選可以正常倒數計時,完了下次就不行了……我已經找到問題所在,不過還是留給你解決吧。

    回顧一下,溫故知新:

  • Qt Quick 簡介
  • QML 語言基礎
  • Qt Quick 之 Hello World 圖文詳解
  • Qt Quick 簡單教程
  • Qt Quick 事件處理之信号與槽

繼續閱讀