事件处理之鼠标键盘定时器----(Qt Quick 教程五)

本文介绍了Qt中鼠标、键盘和定时器事件的处理方法。MouseArea对象可处理鼠标事件,有多个属性和信号;Keys对象用于处理按键事件,有enabled、forwardTo和priority等属性;QML中的Timer代表定时器,可响应onTriggered信号,还有interval、repeat等属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们来看看如何处理鼠标、键盘、定时器等事件。这些时间在处理时,通常是通过信号来完成的。

鼠标事件处理

   看一个简单的处理鼠标事件的例子,先看代码(handle_mouse.qml):

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){
                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";
        }
    }
}

 

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 帮助。
 

 

键盘事件处理

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

    现在再来解释下示例代码。

    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() 三个方法可以调用
 

import QtQuick 2.0
import QtQuick.Controls 1.1
 
Rectangle {
    width: 320;
    height: 240;
    color: "gray";
    QtObject{
        id: attrs;
        property int counter;
        Component.onCompleted:{
            attrs.counter = 10;
        }
    }
    
    Text {
        id: countShow;
        anchors.centerIn: parent;
        color: "blue";
        font.pixelSize: 40;
    }
    
    Timer {
        id: countDown;
        interval: 1000;
        repeat: true;
        triggeredOnStart: true;
        onTriggered:{
            countShow.text = attrs.counter;
            attrs.counter -= 1;
            if(attrs.counter < 0)
            {
                countDown.stop();
                countShow.text = "Clap Now!";
                attrs.counter = 10
            }
        }
    }
    
    Button {
        id: startButton;
        anchors.top: countShow.bottom;
        anchors.topMargin: 20;
        anchors.horizontalCenter: countShow.horizontalCenter;
        text: "Start";
        onClicked: {
            countDown.start();
        }
    }
}

计数保存在 QtObject 对象中, id 是 attrs ,在附加信号处理器 Component.onCompleted 中初始化 counter 属性的值为 10 。而在 Timer 对象的 onTriggered 信号处理器中递减 counter ,当 counter 为 0 时修改 Text 对象的文本为 "Clap Now!" 。
 

去年应朋友需要用C# 2.0写的一个按热键模拟鼠标单击操作程序,类似按键精灵,翻出来分享 实现功能:设定模拟鼠标单击/秒次的系统热键(热键自动保存),设定每秒单击的间隔毫秒数,按下设定好的热键程序便开始模拟鼠标单击操作,再按一次热键程序停止模拟并统计模拟鼠标单击的次数与时间误差。 演示程序:\HookSimulateMouse\bin\Debug\HookSimulateMouse.exe(需MS .NET Framework 2.0运行库支持) 程序界面: 1.设定时间间隔范围:1ms-1000ms,如:900ms 2.设置快捷键,如:Ctrl+Alt+W 将鼠标移至要模拟单击处按热键,于下一秒开始后计时,windowsXP不是实时系统,系统时间误差在20-55ms,而且通过程序获得(特别在CPU占用率高时)都会有延迟,要高精度需要凋API或者取CPU时钟频率,还要计算开机以来运行时长ms数,而且那是计时不是定时。 如:您设定系统时间ms数为900,于5点18分20秒569毫秒按下了快捷键,程序从下一秒0ms开始计时,在5点18分21秒900-908毫秒之间程序模拟一次鼠标单击(鼠标单击可能有8ms延迟) 以此类推直到您再按一次热键程序停止模拟并统计单击次数及毫秒误差(1s=1000ms) 按关闭X或双击桌面右下角系统托盘程序图标可隐藏/显示程序界面,至桌面右下角系统托盘 通过本C#程序源码可学习: 程序窗体最大化/最小化还原到系统托盘 调用系统DLL(user32.dll)设定全局热键控制程序,模拟鼠标单击操作 调用timer控件计时 Thread线程控制 FileStream文件流读写操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlexFang0904

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值