Skip to content
KerwinKoo edited this page Dec 26, 2015 · 14 revisions

Qt5.4 QML 事件处理(鼠标、键盘、定时器)

MouseArea

MouseArea 对象可以附加到一个 item 上供 item 处理鼠标事件,它本身是一个不可见的 item 。在其内部,可以直接引用它所附着的对象的属性和方法。你可以将 MouseArea 理解为它所附着的 item 的代理。

MouseArea 有很多属性

enabled

用来控制是否处理鼠标事件,默认值是 true ,如果你设置为 false ,那么它所代理的 item 就会无视鼠标事件。

acceptedButtons

设定接收拿些个鼠标按键产生的事件(左键、右键、中键).

示例代码 acceptedButtons: Qt.LeftButton | Qt.RightButton; 表示处理鼠标左键和右键。

anchors

作为一个 item , MouseArea 也拥有 anchors 属性,你可以使用它来描述有效的鼠标区域。示例代码 "anchors.fill: parent;" 表示整个矩形区域都接受鼠标事件。

MouseArea 还有很多其他属性,如 hoverEnabled , pressed 等等,请参考 Qt 帮助文档。


示例代码中,在 MouseArea 对象内使用了 onClicked 和 onDoubleClicked 两个信号处理器,他们对应 MouseArea 的 onClickedonDoubleClicked 信号, MouseArea 还有很多其他的信号,如 onPressed / onReleased / onEntered / onExited / onPressAndHold 等等,从名字上就可以看到这些信号的含义。

onClicked 信号的参数是 MouseEvent 类型,名为 mouse ,所以你可以在信号处理器中直接使用 mouse 来查询鼠标事件的详情。比如哪个 button 按下,正如示例代码中看到的那样, MouseEvent 的 button 属性保存了被按下的鼠标按键标记, x , y 属性保存鼠标指针位置。还有一个比较重要的属性 accepted ,如果你处理鼠标事件后不想这个事件再往下传递,就置其值为 true 。

onDoubleClicked 信号代表双击事件,其参数也是 MouseEvent 类型,示例中双击鼠标,矩形颜色变为灰色。

简单的鼠标事件处理就这些内容,根据你应用的需要,可能你还会处理 onPressed / onReleased / onEntered 等等信号。

示例代码:

import QtQuick 2.0
import QtQuick.Controls 1.1

Rectangle {
    width: 320;
    height: 240;
    
    MouseArea {
        anchors.fill: parent;
       
        acceptedButtons: Qt.LeftButton | Qt.RightButton;//处理鼠标左键和右键。
        onClicked: {
            if(mouse.button == Qt.RightButton){	//使用 mouse 来查询鼠标事件的详情
                Qt.quit();
            }
            else if(mouse.button == Qt.LeftButton){
                color = Qt.rgba((mouse.x % 255) / 255.0 , (mouse.y % 255) / 255.0, 0.6, 1.0);//根据鼠标位置改变颜色
            }
        }
        onDoubleClicked: {
            color = "gray";
        }
    }
}

键盘事件处理

手机上键盘事件最重要的为BACK 按键处理

会动的文本实例:

import QtQuick 2.0
import QtQuick.Controls 1.1

Rectangle {
    width: 320;
    height: 480;
    color: "gray";
    
    focus: true;
    Keys.enabled: true;
    Keys.onEscapePressed: {
        Qt.quit();
    }
    Keys.forwardTo: [moveText, likeQt];
    
    Text {
        id: moveText;
        x: 20;
        y: 20;
        width: 200;
        height: 30;
        text: "Moving Text";
        color: "blue";
        //focus: true;
        font { bold: true; pixelSize: 24;}
        Keys.enabled: true;
        Keys.onPressed: {
            switch(event.key){
            case Qt.Key_Left:
                x -= 10;
                break;
            case Qt.Key_Right:
                x += 10;
                break;
            case Qt.Key_Down:
                y += 10;
                break;
            case Qt.Key_Up:
                y -= 10;
                break;
            default:
                return;
            }
            event.accepted = true;//每次按键结束后禁止信号传递
        }
    }
    
    CheckBox {
        id: likeQt;
        text: "Like Qt Quick";
        anchors.left: parent.left;
        anchors.leftMargin: 10;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 10;
        z: 1;
    }
}

说明:

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 即可。

Timer定时器

在 QML 中, Timer 代表定时器,使用起来也很简单,响应其 onTriggered() 信号即可,它也就这么一个有用的信号。

另外它还有几个属性要说明一下:

interval

指定定时周期,单位是毫秒,默认值是 1000 毫秒;

repeat

设定定时器是周期性触发还是一次性触发,默认是一次性的(好像和 QTimer 不一样嗳);

running

设置为 true 定时器就开始工作,设置为 false 就歇菜,默认是 false ;

###triggeredOnStart 属性

怎么说呢, Qt 总是对我们这么好都有点儿那啥不好意思了,这个属性是考虑到有些同志的特殊需求,本来定时器启动后要等待设定的间隔才触发,如果你设置这个属性为 true ,那定时器开始执行时立马先触发一次,默认值是 false 。


Timer 还有 start() / stop() / restart() 三个方法可以调用,它们会影响 running 属性

代码举例:

import QtQuick 2.3
import QtQuick.Controls 1.2

Rectangle {
//    property alias mouseArea: mouseArea

    width: 360
    height: 360

    QtObject {	//用于逻辑计算,不会在页面中显示。这里如果用别的代替(如Item,Component),则不能新定义属性类型
        id: attrs
        property int counter	//定义一个int型变量,counter
        Component.onCompleted: {
            attrs.counter = 10	//组件初始化
        }
    }

    Text {
        id: countshow
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
        anchors.topMargin: 35
        text: "Hello World"
    }

    Timer {
        id: countdown
        interval: 1000		//执行周期,单位为毫秒
        repeat: true		//周期性触发,默认为false,若循环触发需要改为true
        triggeredOnStart: true	//第一次启动即立即触发一次。若为false,则第一次启动先走周期
        onTriggered: {		//启动触发器(onTriggered 信号处理器)
            countshow.text = attrs.counter
            attrs.counter -= 1	//执行递减
            if(attrs.counter < 0)
            {
                countdown.stop()//停止计时器
                countshow.text = "Time OVER!"
                attrs.counter = 10//允许再次启动
            }
        }

    }

    Rectangle {
        width: 100
        height: 35
        color:"blue"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 20
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            onPressed: {
                countdown.start()		//启动计时器
            }
        }
    }
}

[[TOC]]

Clone this wiki locally