qt自定义窗口在拖动过程中出现抖动且拖动后位置看上去不对

2024-04-08 13:20

本文主要是介绍qt自定义窗口在拖动过程中出现抖动且拖动后位置看上去不对,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

自定义窗口拖动

  • 引言
  • 开发环境
  • 关键性代码
  • 运行结果
  • 原因分析
  • 改进代码
  • 运行结果
  • globalPos()
  • globalPosition()
  • 再次修改代码
  • 运行结果
  • 区别

引言

本文旨在一个问题的记录:自定义窗口拖动的过程中,窗口不能很好的跟随鼠标移动,此外会出现窗口拖动时抖动。
下面是上文描述的效果:

拖动时窗口抖动


本文针对上面的问题,找出解决方法,且说明为什么。

开发环境

使用QtCreator开发。其相关的Qt库使用Qt6.6.0。
在这里插入图片描述

关键性代码

这里只给出自定义窗口拖动功能需要的部分关键代码。

    //窗口拖动相关变量声明QPointF m_pressPos;//鼠标按下时位置QPointF m_topLeftPos;//自定义窗口左上角的位置bool m_isPress;//鼠标左键是否按下//功能函数定义
void QCustomWidget::mousePressEvent(QMouseEvent *event)
{qDebug()<<"mousePressEvent";if(event->button() == Qt::LeftButton){m_pressPos = event->position();//相对于接收事件的窗口或者项,事件发生时的位置坐标m_topLeftPos = geometry().topLeft();m_isPress = true;}qDebug()<<"m_pressPos="<<m_pressPos<<", m_topLeftPos="<<m_topLeftPos;QWidget::mousePressEvent(event);
}void QCustomWidget::mouseReleaseEvent(QMouseEvent *event)
{m_isPress = false;QWidget::mouseReleaseEvent(event);
}void QCustomWidget::mouseMoveEvent(QMouseEvent *event)
{qDebug()<<"mouseMoveEvent";if(m_isPress && event->type() == QEvent::MouseMove){QPointF nowPos= event->position();qDebug()<<"nowPos="<<nowPos;move(QPoint((m_topLeftPos + nowPos - m_pressPos).x(),(m_topLeftPos + nowPos - m_pressPos).y()));qDebug()<<"x:"<<(m_topLeftPos + nowPos - m_pressPos).x()<<",y:"<<(m_topLeftPos + nowPos - m_pressPos).y();}QWidget::mouseMoveEvent(event);
}

以上只给主要相关代码,看懂就行。

运行结果

按照上面的代码运行之后,其效果就是本文开头所述那样,窗口拖动过程中出现抖动,且窗口不能实时跟随鼠标。

原因分析

上述代码中,鼠标按下函数mousePressEvent的实现代码里,获取鼠标按下的位置,使用m_pressPos = event->position();即position()来得到鼠标按下的位置。position()获取的位置相对于其所在的窗口或图形项,一般用于图形视图框获取图形项的位置。

在以前可能没有问题,但是qt6中便明确指出:
在这里插入图片描述
当移动窗口来响应鼠标事件,使用globalPosition()来代替position()。

顺便来看一下pos()的官方描述:
在这里插入图片描述
返回相对于接收事件的窗口,鼠标光标所在的位置。Qt6让使用position()代替pos()。
经实践所知,使用pos()与position()获得的鼠标位置,在窗口拖动中都出现抖动或者窗口不能及时跟随鼠标移动的现象。

改进代码

将之前使用position()获取坐标位置的地方改为globalPos(),且将之前QPointF类型的变量 m_pressPos与m_topLeftPos改为QPoint 类型。因为globalPos()返回值类型为QPoint 。

    //窗口拖动QPoint m_pressPos;QPoint m_topLeftPos;bool m_isPress;void QCustomWidget::mousePressEvent(QMouseEvent *event)
{qDebug()<<"mousePressEvent";if(event->button() == Qt::LeftButton){m_pressPos = event->globalPos();m_topLeftPos = geometry().topLeft();m_isPress = true;}qDebug()<<"m_pressPos="<<m_pressPos<<", m_topLeftPos="<<m_topLeftPos;QWidget::mousePressEvent(event);
}void QCustomWidget::mouseReleaseEvent(QMouseEvent *event)
{m_isPress = false;QWidget::mouseReleaseEvent(event);
}void QCustomWidget::mouseMoveEvent(QMouseEvent *event)
{qDebug()<<"mouseMoveEvent";if(m_isPress && event->type() == QEvent::MouseMove){QPoint nowPos= event->globalPos();qDebug()<<"nowPos="<<nowPos;move(QPoint((m_topLeftPos + nowPos - m_pressPos).x(),(m_topLeftPos + nowPos - m_pressPos).y()));qDebug()<<"x:"<<(m_topLeftPos + nowPos - m_pressPos).x()<<",y:"<<(m_topLeftPos + nowPos - m_pressPos).y();}QWidget::mouseMoveEvent(event);
}

再去运行程序,就能够正常拖动窗口了,不会出现抖动和窗口不能及时跟随鼠标移动的情况。

运行结果

拖动窗口

globalPos()

关于函数globalPos(),官方给出的描述如下:
在这里插入图片描述
但发现官方也在Qt6中要求近可能不使用globalPos(),已经在Qt6被抛弃,避免在新的代码中使用。使用globalPosition().toPoint()来代替。

globalPosition()

官方的描述如下:
在这里插入图片描述
于是即使上述的globalPos()可以解决原来的窗口拖动时的抖动和窗口不能及时跟随鼠标移动问题,但还是使用globalPosition()来实现一下看看吧。

再次修改代码

将globalPos()改为globalPosition().toPoint()来获取鼠标的位置。

void QCustomWidget::mousePressEvent(QMouseEvent *event)
{qDebug()<<"mousePressEvent";if(event->button() == Qt::LeftButton){m_pressPos = event->globalPosition().toPoint();m_topLeftPos = geometry().topLeft();m_isPress = true;}qDebug()<<"m_pressPos="<<m_pressPos<<", m_topLeftPos="<<m_topLeftPos;QWidget::mousePressEvent(event);
}void QCustomWidget::mouseReleaseEvent(QMouseEvent *event)
{m_isPress = false;QWidget::mouseReleaseEvent(event);
}void QCustomWidget::mouseMoveEvent(QMouseEvent *event)
{qDebug()<<"mouseMoveEvent";if(m_isPress && event->type() == QEvent::MouseMove){QPoint nowPos= event->globalPosition().toPoint();qDebug()<<"nowPos="<<nowPos;move(QPoint((m_topLeftPos + nowPos - m_pressPos).x(),(m_topLeftPos + nowPos - m_pressPos).y()));qDebug()<<"x:"<<(m_topLeftPos + nowPos - m_pressPos).x()<<",y:"<<(m_topLeftPos + nowPos - m_pressPos).y();}QWidget::mouseMoveEvent(event);
}

运行结果

其结果与使用globalPos()一样,都解决了窗口拖动时的抖动和不能及时跟随鼠标移动的问题。

区别

下面为pos(),globalPos(),globalPosition(),position()的区别:

pos():
这个函数返回控件在其父控件坐标系中的位置。

返回一个QPoint对象,表示控件左上角相对于其父控件的x和y坐标。
如果控件没有父控件(即它是一个顶级窗口),则pos()返回的是相对于屏幕的坐标。

globalPos():
这个函数返回控件在全局屏幕坐标系中的位置。
同样返回一个QPoint对象,但表示的是控件左上角相对于整个屏幕的x和y坐标。
这对于顶级窗口和子控件都适用,因为它总是返回屏幕上的绝对位置。

globalPosition():
这个函数与globalPos()的功能基本相同, 都返回控件在全局屏幕坐标系中的位置。

返回的也是QPoint对象,表示控件在屏幕上的绝对位置。
在某些版本的Qt中,globalPosition()可能是globalPos()的同义词或别名。Qt6之后推荐使用globalPosition()。

position():
这个函数通常用于QGraphicsItem,在Qt的图形视图框架中。

它返回该图形项在其父项或场景中的位置。
返回一个QPointF对象,表示图形项左上角的x和y坐标。

这篇关于qt自定义窗口在拖动过程中出现抖动且拖动后位置看上去不对的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/885706

相关文章

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

SpringBoot整合liteflow的详细过程

《SpringBoot整合liteflow的详细过程》:本文主要介绍SpringBoot整合liteflow的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋...  liteflow 是什么? 能做什么?总之一句话:能帮你规范写代码逻辑 ,编排并解耦业务逻辑,代码

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

MySQL中的InnoDB单表访问过程

《MySQL中的InnoDB单表访问过程》:本文主要介绍MySQL中的InnoDB单表访问过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、访问类型【1】const【2】ref【3】ref_or_null【4】range【5】index【6】

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam