QT Qml中相应pressed却不响应released问题解决

本文分享了在使用QML进行UI开发时,MouseArea在失去焦点后不再响应事件的问题及解决方案。通过设置activeFocusOnTab属性为true,解决了因切换窗口或虚拟按键导致的后续事件不响应问题。

qml好用啊,可是有点小坑要填,填坑过程也很有趣

遇到问题MouseArea在pressed后,切出焦点(windows下tab切换窗口,android下切出虚拟按键) 导致不响应后续事件

直接上结果

activeFocusOnTab: true;

打log观察activeFocus过程中偶然发现的,不知道有没有副作用,发出来是想帮助同样掉坑的同学;-)

转载于:https://my.oschina.net/flywuya/blog/757745

<think>在QML中,`MultiPointTouchArea`主要用于处理多点触摸事件,但它本身并直接支持双击事件。过,我们可以通过结合`Timer`事件处理来实现双击检测。以下是实现双击事件的步骤: 1. 记录每次触摸点的按下事件。 2. 使用一个计时器来判断两次点击的时间间隔是否在设定的双击时间范围内。 3. 如果两次点击的时间间隔小于阈值,则触发双击事件。 由于`MultiPointTouchArea`可以跟踪多个触摸点,我们需要为每个触摸点单独跟踪点击事件。但是,双击通常只关注单个点的连续两次点击。因此,我们可以只跟踪第一个触摸点的双击事件,或者根据需求设计。 以下是一个示例代码,演示如何在`MultiPointTouchArea`中实现双击事件: ```qml import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 400 height: 400 title: "MultiPointTouchArea Double Click" Rectangle { id: touchAreaRect anchors.fill: parent color: "lightgray" MultiPointTouchArea { id: touchArea anchors.fill: parent minimumTouchPoints: 1 maximumTouchPoints: 2 // 用于记录上一次点击的时间 property var lastClickTime: 0 // 双击时间阈值(毫秒) property int doubleClickThreshold: 300 touchPoints: [ TouchPoint { id: point1 }, TouchPoint { id: point2 } ] onPressed: { // 当有触摸点按下时,检查时间间隔 var currentTime = new Date().getTime(); if (currentTime - lastClickTime < doubleClickThreshold) { // 触发双击事件 console.log("Double click detected!"); // 执行双击操作 doubleClickDetected(); // 重置时间,避免连续三次点击触发两次双击 lastClickTime = 0; } else { // 第一次点击,记录时间 lastClickTime = currentTime; } } } function doubleClickDetected() { // 双击事件处理 touchAreaRect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } } ``` **代码解释:** 1. **属性定义:** - `lastClickTime`:记录上一次点击的时间戳(毫秒)。 - `doubleClickThreshold`:双击时间间隔阈值,这里设置为300毫秒(通常双击间隔在300-500毫秒内)。 2. **onPressed处理:** - 当触摸点按下时(`onPressed`信号被触发),获取当前时间。 - 判断当前时间与上一次点击时间的间隔是否小于阈值: - 如果小于阈值,则触发双击事件(调用`doubleClickDetected`函数),并重置`lastClickTime`为0(避免第三次点击再次触发双击)。 - 否则,记录当前时间作为`lastClickTime`。 3. **双击事件处理:** - 在`doubleClickDetected`函数中,我们简单地改变矩形的颜色作为演示。 **注意:** - 上述代码只检测第一个触摸点的双击事件(因为`onPressed`信号在任意触摸点按下时都会触发,且我们只记录了一个时间)。如果要区分同的触摸点,需要为每个触摸点单独记录时间。但是,双击通常是由同一个触摸点(或同一个位置)的连续两次点击触发的,因此上述实现对于大多数情况已经足够。 - 如果要求更精确的双击(比如要求两次点击在相近的位置),可以增加位置判断,记录上一次点击的位置并与当前点击位置进行比较。 **改进版本(增加位置判断):** ```qml import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 400 height: 400 title: "MultiPointTouchArea Double Click with Position" Rectangle { id: touchAreaRect anchors.fill: parent color: "lightgray" MultiPointTouchArea { id: touchArea anchors.fill: parent minimumTouchPoints: 1 maximumTouchPoints: 2 property double lastClickTime: 0 property int doubleClickThreshold: 300 property point lastClickPos: Qt.point(0,0) property double posThreshold: 20 // 位置允许的偏移阈值 touchPoints: [ TouchPoint { id: point1 }, TouchPoint { id: point2 } ] onPressed: { var currentTime = new Date().getTime(); var currentPos = touchPoints[0].startX; // 取第一个触摸点的位置 if (currentTime - lastClickTime < doubleClickThreshold) { // 检查位置是否在阈值范围内 if (Math.abs(currentPos.x - lastClickPos.x) < posThreshold && Math.abs(currentPos.y - lastClickPos.y) < posThreshold) { console.log("Double click detected at", currentPos); doubleClickDetected(); lastClickTime = 0; } else { // 位置超出范围,更新为本次点击的时间位置 lastClickTime = currentTime; lastClickPos = currentPos; } } else { lastClickTime = currentTime; lastClickPos = currentPos; } } } function doubleClickDetected() { touchAreaRect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } } ``` 在这个改进版本中,我们增加了: - `lastClickPos`:记录上一次点击的位置。 - `posThreshold`:位置偏移的阈值(像素)。 - 在判断双击时,除了时间间隔,还要求两次点击的位置在阈值范围内。 **注意:** 这里我们只取了第一个触摸点(`touchPoints[0]`)的位置。如果你需要支持多个触摸点的双击,需要为每个触摸点单独记录,但通常双击事件只关注主触摸点。 §§相关问题§§: 1. 在QML中,如何区分单点触摸多点触摸事件? 2. 如何实现QML中触摸手势的识别(如捏合、旋转)? 3. 如何处理QML中触摸事件的冲突(例如父元素子元素同时处理触摸事件)? 4. 在QML中,如何检测长按触摸事件?</think># QML 中 MultiPointTouchArea 响应双击事件实现方案 在 QML 中,`MultiPointTouchArea` 主要用于处理多点触控事件,但它本身直接支持双击事件检测。要实现双击事件响应,我们需要结合计时器状态管理来识别双击手势。以下是完整的实现方案: ## 基本实现方案 ```qml import QtQuick 2.6 import QtQuick.Controls 2.0 Item { width: 400 height: 400 Rectangle { id: touchArea anchors.fill: parent color: "lightblue" MultiPointTouchArea { id: multiTouch anchors.fill: parent minimumTouchPoints: 1 maximumTouchPoints: 5 // 双击检测相关属性 property bool touchPressed: false property int touchCount: 0 property double lastTouchTime: 0 property double doubleClickTimeout: 300 // 双击时间阈值(毫秒) // 检测双击事件 function checkForDoubleTouch(point) { var currentTime = new Date().getTime(); if (touchPressed && (currentTime - lastTouchTime) < doubleClickTimeout) { touchCount++; if (touchCount === 2) { console.log("Double touch detected at", point.x, point.y); doubleTouchDetected(point); } } else { touchCount = 1; } lastTouchTime = currentTime; touchPressed = true; } // 双击事件处理函数 function doubleTouchDetected(point) { // 实现双击响应逻辑 console.log("Double touch handled at", point.x, point.y); touchArea.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); // 重置状态 touchCount = 0; touchPressed = false; } // 触摸点按下处理 onPressed: { for (var i = 0; i < touchPoints.length; i++) { if (touchPoints[i].pressed) { checkForDoubleTouch(touchPoints[i]); } } } // 触摸点释放处理 onReleased: { touchPressed = false; // 设置重置计时器 resetTimer.start(); } // 重置状态计时器 Timer { id: resetTimer interval: multiTouch.doubleClickTimeout * 1.5 onTriggered: { multiTouch.touchCount = 0; multiTouch.touchPressed = false; } } } Text { anchors.centerIn: parent text: "双击区域" font.pixelSize: 24 } } } ``` ### 代码解释 1. **双击检测逻辑**: - `checkForDoubleTouch()` 函数检测连续两次触摸的时间间隔 - `doubleClickTimeout` 定义双击识别的时间窗口(300毫秒是常见值) - `touchCount` 跟踪连续触摸次数 2. **事件处理流程**: - `onPressed`:当触摸点按下时,检查是否满足双击条件 - `onReleased`:当触摸点释放时,启动重置计时器 - `resetTimer`:确保在超时后重置双击状态 3. **状态管理**: - `touchPressed` 跟踪当前是否有触摸点处于按下状态 - `lastTouchTime` 记录上次触摸的时间戳 - `touchCount` 记录连续触摸次数 4. **双击响应**: - `doubleTouchDetected()` 函数处理双击事件 - 示例中随机改变背景颜色作为响应 ## 进阶实现:区分单点多点双击 ```qml import QtQuick 2.6 import QtQuick.Controls 2.0 Item { width: 600 height: 400 // 单点双击区域 Rectangle { id: singleTouchArea width: parent.width / 2 height: parent.height color: "lightgreen" MultiPointTouchArea { anchors.fill: parent onPressed: { if (touchPoints.length === 1) { detectDoubleTouch(touchPoints[0], "single"); } } } Text { anchors.centerIn: parent text: "单点双击区域" font.pixelSize: 20 } } // 多点双击区域 Rectangle { id: multiTouchArea x: parent.width / 2 width: parent.width / 2 height: parent.height color: "lightblue" MultiPointTouchArea { anchors.fill: parent onPressed: { if (touchPoints.length >= 2) { detectDoubleTouch(null, "multi"); } } } Text { anchors.centerIn: parent text: "多点双击区域" font.pixelSize: 20 } } // 双击检测逻辑 function detectDoubleTouch(point, type) { var currentTime = new Date().getTime(); if (lastTouchTime[type] && (currentTime - lastTouchTime[type]) < doubleClickTimeout) { touchCount[type]++; if (touchCount[type] === 2) { console.log(type + " double touch detected"); if (type === "single") { singleTouchArea.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } else { multiTouchArea.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } touchCount[type] = 0; } } else { touchCount[type] = 1; } lastTouchTime[type] = currentTime; } // 双击检测状态 property var lastTouchTime: ({"single": 0, "multi": 0}) property var touchCount: ({"single": 0, "multi": 0}) property double doubleClickTimeout: 300 } ``` ### 代码解释 1. **区分单点多点双击**: - 左侧区域检测单点双击(一个手指) - 右侧区域检测多点双击(两个或更多手指) 2. **状态管理优化**: - 使用字典存储同类型双击的状态 - `lastTouchTime` `touchCount` 分别记录每种类型的时间戳计数 3. **统一检测函数**: - `detectDoubleTouch()` 处理所有类型的双击检测 - 根据类型参数执行同的响应逻辑 ## 最佳实践与注意事项 1. **时间阈值选择**: - 通常 200-500ms 是合理的双击识别窗口 - 可通过用户设置调整:`doubleClickTimeout = settings.doubleClickInterval` 2. **位置一致性检测**: ```qml property point lastTouchPosition: Qt.point(0, 0) property double positionThreshold: 20 // 像素 function isNearPreviousPosition(point) { return Math.abs(point.x - lastTouchPosition.x) < positionThreshold && Math.abs(point.y - lastTouchPosition.y) < positionThreshold; } ``` 在双击检测中加入位置检查,确保两次触摸在相近位置 3. **性能优化**: - 避免在`onPressed`中执行复杂操作 - 使用`Timer`代替`setTimeout`确保事件循环正常 - 复杂场景下使用`TouchPoint`的`id`跟踪特定触摸点 4. **触摸点跟踪**: ```qml property var activeTouches: ({}) onPressed: { for (var i = 0; i < touchPoints.length; i++) { var touch = touchPoints[i]; activeTouches[touch.pointId] = { id: touch.pointId, startTime: new Date().getTime(), position: Qt.point(touch.x, touch.y) }; } } ``` 使用字典按ID跟踪触摸点,处理更复杂的交互
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值