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

相关文章

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT