当前位置: 首页 > news >正文

QML学习笔记(十五)QML的信号处理器(MouseArea)

前言

从本节开始,我们将详细学习有关QML的信号与槽机制。因为我已经对QWidget中的信号槽机制有比较全面的了解,所以在接下来的学习中可能会进行一些对比。
本节中介绍的信号处理器,其实可以理解为所谓的槽函数。比如之前已经使用过的MouseArea,我们实现了它的onClicked,这就是一个信号处理器。

一、MouseArea的信号处理器

在实际开发中,如何监听和处理鼠标相关事件是一个重要的事情。除了此前所用过的单击事件,还有一系列常用的行为,例如双击、滚轮,甚至还有进入、离开等等。我们将逐个进行学习和演示。
先创建一个新工程,命名为QmlSignalHandlers,并创建一个测试矩形,绑定一个MouseArea:

Window {visible: truewidth: 640height: 480title: qsTr("QmlSignalHandlers")Rectangle{id: rectIdwidth: 150height: 150color: "red"MouseArea{anchors.fill: parent}}
}

然后我希望实现一系列鼠标相关的处理器。我们可以先在帮助文档搜索一下:
在这里插入图片描述
往下划,它有相当多的属性:
在这里插入图片描述
然后,它还有那么多的信号:
在这里插入图片描述
而这些信号,我们都可以实现它们对应的信号处理器,也就是信号对应的槽函数。

二、鼠标单击和双击

我们先从最简单的开始,我们之前已经使用过onClicked,我们直接模仿一下,实现onDoubleClicked:

MouseArea{anchors.fill: parentonClicked: {console.log("click...");}onDoubleClicked: {console.log("double click...");}
}

我们手动敲代码的时候应该能感受到,编辑器可以给我们进行快速补全,这非常方便我们的开发。
运行后,我们先单击矩形:
在这里插入图片描述
后双击矩形:
在这里插入图片描述
这意味着什么?意味着双击的行为也会触发一次单击的行为,这一点一定要注意,不然会导致一些逻辑代码的混乱。不过好在我们默认情况下,实现了双击就不会实现单击。

三、鼠标事件进入、离开、取消

首先介绍一个MouseArea的属性,那就是hoverEnabled,你必须把它设置成true,才可以监听实现鼠标覆盖的事件。比方说我鼠标移动上去,但并没有点击,此时我希望能触发相关事件,那我们就必须要设置这个标志。

hoverEnabled: true

你可能一下子没想到这个东西的应用,实际上是非常常见的需求。比如我们需要自定义实现鼠标三态控件样式,那我们就需要分别实现鼠标覆盖和鼠标点击的不同样式。再来我们应该都用过鼠标放到窗口边缘,然后通过拖拽改变窗口尺寸的功能,这里需要监听鼠标覆盖事件,改变鼠标图标的样式。
然后,我设置三个处理器:

            onEntered: {console.log("enter...");}onExited: {console.log("exit...");}onCanceled: {console.log("cancel...");}

运行程序,观察现象:
在这里插入图片描述
鼠标刚放上去,就打印了enter;
鼠标左键单击按下,打印了click;
鼠标从矩形的范围移出,打印了exit。
这个逻辑大家应该很好理解吧?我就不多说了。
如果我们没有设置hoverEnabled,那估计鼠标点击的那一刻,才会打印出enter了。
至于onCancel其实是个不常用的处理器,我也没办法触发它。网上的解释是这样的:onCanceled 只有在 拖拽(drag)场景 且 被系统/用户取消 时才会触发,日常点击根本不会进这个处理器。

四、onWheel鼠标滚轮

wheel是鼠标滚轮的意思,我们也可以对其进行监听哦:

onWheel:{console.log("wheel:"+wheel.angleDelta);
}

运行:
在这里插入图片描述

angleDelta的值要不是120,要不是-120。实际上,120在qt当中被处理成15°,angleDelta代表滚动了一格的意思,有兴趣可以自行了解。

五、鼠标的按下、移动和释放

我们已经学会了鼠标点击onClicked使用,但实际上鼠标点击这个行为还可以被拆解为按下、移动和释放三种行为。这个在QWidget中亦有实现:

    void mousePressEvent(QMouseEvent* event)override;void mouseMoveEvent(QMouseEvent* event)override;void mouseReleaseEvent(QMouseEvent* event)override;

在QML的MouseArea中,我们使用onPressed、onPositionChanged和onReleased来实现。下面我们详细实现一下:
1.onPressed点击

acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: {console.log("onPressed", mouse.x, mouse.y)if (mouse.button === Qt.LeftButton)console.log("left press", mouse.x, mouse.y)
}

我们先说一下这句代码:acceptedButtons: Qt.LeftButton | Qt.RightButton。
事实上鼠标点击是可以监听左键和右键的,但默认只监听左键。如果你想要实现右键的点击,需要给MouseArea设置接收的按钮,也就是acceptedButtons。
既然都可以接收多种按钮了,那自然onPressed里面也要有对应的区分。这里用到了全局对象当中的Qt.LeftButton。
以上功能都很常见,甚至都是标准写法了,在QWidget中也有对应的实现。
2.onPositionChanged移动
它这里写的比mouseMoveEvent稍微复杂一点,但意思都是鼠标移动了。我们可以打印实时坐标。

onPositionChanged: {console.log("onPositionChanged:", mouse.x, mouse.y)
}

这个处理器触发得比较频繁,如果影响查看打印信息的话,可以暂时屏蔽掉它。
3.onReleased松开
鼠标按下后松开的时刻会触发:

onReleased: {console.log("onReleased:", mouse.x, mouse.y)
}

以上三个处理器基本上都是搭配一起使用的,以实现一些复杂的业务逻辑,最典型的就是鼠标拖拽。
我们可以尝试实现它!

六、简单实现鼠标拖拽控件移动

我尝试了自行实现,思路是设置几个自定义的属性,记录鼠标按下的那一刻的坐标,然后在移动时实时计算偏移坐标并进行计算和设置,但效果不是很好,存在跳闪情况,这是我的完整代码:

Window {visible: truewidth: 640height: 480title: qsTr("QmlSignalHandlers")Rectangle{id: rectIdwidth: 150height: 150color: "red"MouseArea{property bool isPressed: falseproperty int anchorX: 0          // 按下时鼠标相对矩形的xproperty int anchorY: 0          // 按下时鼠标相对矩形的yproperty int rectX: 0          // 按下时鼠标相对矩形的xproperty int rectY: 0          // 按下时鼠标相对矩形的yanchors.fill: parenthoverEnabled: trueacceptedButtons: Qt.LeftButton | Qt.RightButtononPressed: {console.log("onPressed", mouse.x, mouse.y)if (mouse.button === Qt.LeftButton) {console.log("left press", mouse.x, mouse.y)isPressed = true;// 记录按下瞬间鼠标在矩形内的本地坐标anchorX = mouse.x;anchorY = mouse.y;rectX = rectId.x;rectY = rectId.y;}}onPositionChanged: {console.log("onPositionChanged:", mouse.x, mouse.y)if (isPressed) {// 鼠标全局坐标 - 锚点 = 矩形新左上角rectId.x = rectX + mouse.x - anchorX;rectId.y = rectY + mouse.y - anchorY;}}onReleased: {console.log("onReleased:", mouse.x, mouse.y)isPressed = false;}}}
}

我觉得稍微复杂的点是,MouseArea的坐标是相对于Rectangle的,但实际移动的却是矩形。
我让ai帮我重新设计了一个,这段代码效果更好,拖拽起来效果很正常:

Window {visible: truewidth: 640height: 480title: qsTr("DragRect")Rectangle {id: rectIdwidth: 150; height: 150; color: "red"MouseArea {anchors.fill: parentacceptedButtons: Qt.LeftButtonhoverEnabled: trueproperty bool pressed: falseproperty real startSceneX: 0   // 按下时全局坐标property real startSceneY: 0property real startRectX: 0    // 按下时矩形左上角property real startRectY: 0onPressed: {pressed = truevar scenePos = mapToItem(null, mouse.x, mouse.y)   // 映射到窗口坐标startSceneX = scenePos.xstartSceneY = scenePos.ystartRectX  = rectId.xstartRectY  = rectId.y}onPositionChanged: {if (pressed) {var curScene = mapToItem(null, mouse.x, mouse.y)rectId.x = startRectX + (curScene.x - startSceneX)rectId.y = startRectY + (curScene.y - startSceneY)}}onReleased: pressed = false}}
}

实现思路大差不差,但它将鼠标事件的坐标转化为顶层窗口的相对坐标了。
mapToItem 这个接口就是实现了这个功能。
target 填谁,就返回相对于谁的坐标
target == null 时特指顶层窗口(rootItem)坐标,俗称“全局坐标”
返回值是 point{x: …, y: …}
我认为这个处理还是比较聪明的,就是如果相对的0点坐标不是顶层窗口的话,要记得处理一下,把null改掉。

七、onPressAndHold鼠标按住

onPressAndHold的触发场景是鼠标按下,短时间没有松开的时候,将会被触发。

onPressAndHold:{console.log("onPressAndHold...");
}

我们可以利用这个处理器,对刚才的拖拽效果稍作改造,就可以实现一个长按控件并移动的这样一个功能。这个功能也很常见,不是吗?
当然,如果觉得长按太久,或者长按不够久,我完全可以沿用pressed事件,自己去做时间方面的判断即可。onPressAndHold只是给你提供了一个快速的使用入口。

八、总结

本章算是对MouseArea有一个全面的了解和应用了,但本意其实是借着MouseArea来学习信号处理器的使用。事实上所有常用组件都会有类似的功能,我们需要通过帮助文档或百度来进行学习。这些在后面对每一个组件进行深入学习时,也会有所提及的。

http://www.dtcms.com/a/415640.html

相关文章:

  • php 微信 网站建设无限观影次数的app软件
  • 苏州网站建设数据网络WordPress支付宝登录
  • opcode - Claude Code 图形化工具集
  • 淮南招聘网站建设全球域名注册平台
  • VsCode配置Claude Code-Windows
  • 网站建设台词精品课程网站设计说明范文
  • 手写MyBatis第78弹:装饰器模式在MyBatis二级缓存中的应用:从LRU到防击穿的全方案实现
  • 山西网站开发二次开发拍卖网站功能需求文档
  • 中文简洁网站设计图wordpress 导航菜单设置
  • JavaWeb-Ajax、监听器、过滤器及对应案例和jstl补充
  • 如何自己免费建网站做最优秀的自己演讲视频网站
  • 文件包含与下载漏洞
  • centos7.9下安装freeswitch-1.10.5.-release详细教程(极其简单)
  • 慢慢来做网站多少钱互联网保险经纪公司十大排名
  • 【开题答辩全过程】以 Springboot大学英语四、六级学习系统开题为例,包含答辩的问题和答案
  • php网站开发有什么软件男人女人做性关系网站
  • 网站访客qq获取原理南昌网站开发机构
  • 获取淘宝商品视频API接口解析:通过商品链接url获取商品视频item_video
  • k8s node 节点加入 matser 错误 cannot construct envvars
  • 做个自己的网站需要多少钱桂林网络平台开发公司
  • 网站的建设背景临沂seo推广
  • 网站建设合同免费下载做网页公司有哪些
  • 【TS6】Cherry Studio项目介绍
  • 自己创免费网站网站建设人员构成
  • 永远网站建设推荐商城网站建设
  • 【探寻C++之旅】第十五章:哈希表
  • 线程的生命周期
  • 网站建设男装定位微信公众平台注册官网入口
  • 廊坊seo网站排名ui设计培训班有用吗
  • 公司网站定位建议广州手工活外发加工网