本文的功能实现,参考了链接:https://blog.csdn.net/Ternence_God/article/details/100150377,图片也是来自其。

引言

创建的程序采用系统窗口,直接可以进行拖动,向八个方向拉伸,一旦设置窗口无标题栏,即:setWindowFlags(Qt::FramelessWindowHint);后,窗口的拖动,拉伸功能便需要重新实现。

效果

由于暂时还没有向平台上传视频,所以咱没有插入视频来直观的显示程序运行的效果。后期补上。

实现

开发环境

下面以一个小的demo来实现窗口的拖动和拉伸功能。

思路

窗口的拖动

鼠标按下后记住当前鼠标按下点的位置,这个点相对于屏幕而言,同时获取窗口左上角的位置,当鼠标按下移动后,获取当前移动到的点的位置,也是相对于桌面而言的坐标,用移动后的位置减去刚开始鼠标按下的点得到偏移量,用鼠标左上角的点加上偏移量便是移动后窗口的位置,调用move()函数将窗口移动到指定点,实现窗口在鼠标按下不放可拖动。这里不用考虑偏移量是加上还是减去,因为记录了鼠标刚开始按下的点之后,向右移,偏移量变为正值,向左移偏移量便为负值。

窗口的拉伸

由于我们获取窗口的上下左右四个边以及四个角的坐标来判断当鼠标进入指定边或者角时,两者的坐标并不相同,而是有一定的偏差,这是采用划分区域来实现鼠标进入窗口置顶的边或角,从而按照不同的边、角置顶鼠标的样式,保存原来窗口的位置大小,记录鼠标变样后按下点的坐标,和鼠标移动后点的坐标,求得偏移量,从而计算各个边角的位置,从新设置窗口的位置大小。且需要记录窗口被拉伸后鼠标的位置,防止下一次操作直接从上一次拉伸后不释放坐标直接拉伸。
区域划分

项目结构


基类选择QDialog类,其它都是默认,然后创建项目。

具体代码

.pro,.ui文件采用自动生成的,不做任何改变。
widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
protected:enum mouseArea{topLeftCorner = 11,topBorder = 12,topRightCorner = 13,leftBorder = 21,midArea = 22,rightBorder = 23,leftBottomConrner = 31,bottomBorder = 32,rightBottomConrner = 33,};enum winDivideArea{oneArea = 1,twoArea,threeArea,};void mousePressEvent(QMouseEvent *event);void mouseMoveEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);void setMouseCursorStyle(QMouseEvent *event);//设置鼠标光标的样式int determineArea(QPoint pos);//判断点pos所在的区域void mouseStrechDrag(QMouseEvent *event,QPoint &offset);//鼠标拉伸拖动
private:Ui::Widget *ui;QPoint      m_pressPos;//鼠标按下点的位置QPoint      m_topLeftPos;//鼠标左上角的位置QPoint      m_lastPos;//上一次拉伸点的位置const int   m_floatValue;//鼠标所在位置的浮动值int         m_region;//鼠标所在的区域
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMouseEvent>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent),m_floatValue(10), ui(new Ui::Widget)
{ui->setupUi(this);setWindowFlags(Qt::FramelessWindowHint);setMouseTracking(true);
}Widget::~Widget()
{delete ui;
}void Widget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {//        m_pressPos = event->globalPos();//获取在屏幕坐标系统中的位置
//        m_topLeftPos = geometry().topLeft();//获取窗口左上角的位置,原本采取左上角坐标+偏移量m_lastPos = event->globalPos();m_pressPos = pos();m_region = determineArea(event->pos());//在父窗口中的位置//        qDebug()<<QStringLiteral("鼠标位置:")<<m_pressPos<<QStringLiteral("位置:")<<event->pos()
//        <<QStringLiteral("窗口左上角的位置:")<<m_topLeftPos;//在父窗口中的位置}QWidget::mousePressEvent(event);
}void Widget::mouseMoveEvent(QMouseEvent *event)
{if (isMaximized()){return;}setMouseCursorStyle(event);if (event->buttons() == Qt::LeftButton) {QPoint offset = event->globalPos() - m_lastPos;if (m_region == midArea) {move(m_pressPos + offset);}else {mouseStrechDrag(event,offset);}}QWidget::mouseMoveEvent(event);
}void Widget::mouseReleaseEvent(QMouseEvent *event)
{QWidget::mouseReleaseEvent(event);
}void Widget::setMouseCursorStyle(QMouseEvent *event)
{int region = determineArea(event->pos());//这里的区域必须为局部变量,否则会出现拉伸中出现区域变更,导致功能紊乱switch (region) {case topLeftCorner:case rightBottomConrner:setCursor(Qt::SizeFDiagCursor);//设置光标的形状使用setCursor(),使用setShape()设置不上,并不知为啥break;case topBorder:case bottomBorder:setCursor(Qt::SizeVerCursor);break;case topRightCorner:case leftBottomConrner:setCursor(Qt::SizeBDiagCursor);break;case leftBorder:case rightBorder:setCursor(Qt::SizeHorCursor);break;case midArea:setCursor(Qt::ArrowCursor);break;default:break;}
}int Widget::determineArea(QPoint pos)
{int xArea = 0;int yArea = 0;int areaFlag = 0;if (pos.x() < m_floatValue) {xArea = oneArea;}else if (pos.x() > width() - m_floatValue) {xArea = threeArea;}else {xArea = twoArea;}if (pos.y() < m_floatValue) {yArea = oneArea;}else if (pos.y() > height() - m_floatValue) {yArea = threeArea;}else {yArea = twoArea;}return areaFlag = yArea * 10 + xArea;
}void Widget::mouseStrechDrag(QMouseEvent *event,QPoint &offset)
{QRect rect = geometry();qDebug()<<QStringLiteral("鼠标移动的位置:")<<event->globalPos()<<QStringLiteral("按下点位置:")<<m_pressPos<<QStringLiteral("偏移量:")<<event->globalPos()-m_pressPos;switch (m_region) {case topLeftCorner:rect.setTopLeft(rect.topLeft() + offset);break;case rightBottomConrner:rect.setBottomRight(rect.bottomRight() + offset);break;case topBorder:rect.setTop(rect.top() + offset.y());break;case bottomBorder:rect.setBottom(rect.bottom() + offset.y());break;case topRightCorner:rect.setTopRight(rect.topRight() + offset);break;case leftBottomConrner:rect.setBottomLeft(rect.bottomLeft() + offset);break;case leftBorder:rect.setLeft(rect.left() + offset.x());break;case rightBorder:rect.setRight(rect.right() + offset.x());break;default:break;}//设置拉伸的最小宽度和高度if (rect.width() < 200 || rect.height() < 100) {return ;}setGeometry(rect);m_lastPos = event->globalPos();
}//void Widget::setMouseCursorStyle(QMouseEvent *event)
//{//    //转换后存在误差,鼠标在左下角获取的位置与左下角的位置不一样,因而无法实现下述方法
//    qDebug()<<QStringLiteral("鼠标在父窗口的位置:")<<mapFromParent(event->globalPos())<<
//    QStringLiteral("鼠标的位置:")<<event->pos()<<QStringLiteral("左上角")<<geometry().topLeft()
//    <<QStringLiteral("右上角")<<geometry().topRight()<<QStringLiteral("左下角")<<geometry().bottomLeft()
//    <<QStringLiteral("右下角")<<geometry().bottomRight()<<QStringLiteral("左边")<<geometry().left()
//    <<QStringLiteral("右边")<<geometry().right()<<QStringLiteral("上边")<<geometry().top()
//    <<QStringLiteral("下边")<<geometry().bottom()<<QStringLiteral("转换后左下角")<<mapFromParent(geometry().bottomLeft());//获取位置相同,都是鼠标在父窗口中的位置
//    if (event->pos().x() > geometry().left() &&event->pos().x() < geometry().right()
//    && event->pos().y() > geometry().top() && event->pos().y() < geometry().bottom())
//    {//中间
//        cursor().setShape(Qt::ArrowCursor);
//    }else if (event->pos() == mapFromParent(geometry().topLeft())) {//左上角
//        qDebug()<<QStringLiteral("鼠标在左上角");
//        cursor().setShape(Qt::SizeFDiagCursor);
//    }else if (event->pos() == mapFromParent(geometry().topRight())) {//右上角
//        cursor().setShape(Qt::SizeBDiagCursor);
//    }else if (event->pos() == geometry().bottomLeft()) {//左下角
//        cursor().setShape(Qt::SizeBDiagCursor);
//    }else if (event->pos() == geometry().bottomRight()) {//右下角
//        cursor().setShape(Qt::SizeFDiagCursor);
//    }else if (event->pos().x() == geometry().left()) {//左边
//        cursor().setShape(Qt::SizeHorCursor);
//    }else if (event->pos().x() == geometry().right()) {//右边
//        cursor().setShape(Qt::SizeHorCursor);
//    }else if (event->pos().y() == geometry().top()) {//上边
//        cursor().setShape(Qt::SizeVerCursor);
//    }else if (event->pos().y() == geometry().bottom()) {//下边
//        cursor().setShape(Qt::SizeVerCursor);
//    }
//}

main.cpp文件也采用默认生成的文件。
这样就可以编译,运行,查看程序的运行效果了。

注意点

  1. 理解思路,将窗口划分为9个区域,进行编号,之所以要划分区域是因为上面被注释掉的代码在运行时会发现鼠标即使到了窗口的指定边,但是与获取的指定边的坐标总有偏差。
  2. 需要在构造函数中设置鼠标跟踪,要不不能实现鼠标放置在指定边时出现特定的鼠标样式,只在鼠标点击后才能出现特定 的鼠标样式。

无标题栏窗口的实现拖动,和边的拉伸功能相关推荐

  1. QT实现完美无边框窗口(可拖动,可调整大小)

    效果如下: 只需定义 nativeEvent 事件即可完成这样的功能 ,但要注意的是,这是通过Windows api实现的. 样例如下:(注意头文件) framelesswidget.h #ifnde ...

  2. Electron无边框窗口(最小化、最大化、关闭、拖动)以及动态改变窗口大小

    文章目录 一.目标原型 1. 目标 2. 原型设计 3. 原型初步实现 二.无边框窗口 1. 要点 2. 改造 三.可拖拽区 1. 要点 2. 改造 四.最小化.最大化.关闭 1. 要点 2. 改造 ...

  3. C# 移动窗口 适用于有标题栏和无标题栏窗体 超级简单版

    适用于有标题栏和无标题栏窗体,适用于窗体内控件,当然 Form 也不例外,只要能添加 MouseDown.MouseMove 事件,无需添加 MouseUp 事件,也无需考虑 Form 是否有标题栏. ...

  4. qt禁止拖动_[Qt]QMdiArea,无框架窗口的拖动

    0:QMdiArea中添加子窗口后,想固定or调整窗口的大小 需要在addSubWindow()函数调用后返回子窗口的指针,然后再设置子窗口的大小 注意设置imagelabel的大小是没有效果的,im ...

  5. 【C++·Qt】Qt透明无边框窗口以及拖动

    窗口透明  1.窗口整体透明(包含其子空控件) //窗口以及子控件都透明 //setAttribute(Qt::WA_WState_WindowOpacitySet); //网上说直接设置不起作用,需 ...

  6. 基于Android T代码分析: 在freeform窗口的标题栏拖动时移动窗口流程和拖动freeform窗口边沿改变大小流程

    基于Android T代码分析: 在freeform窗口的标题栏拖动时移动窗口流程和拖动freeform窗口边沿改变大小流程在线看Android源代码网址: http://aospxref.com/a ...

  7. MFC无标题栏对话框移动的处理方法

    很多时候,为了界面的美观,我们会隐藏标题栏,而在客户区通过自绘模拟标题栏.但是这样处理,会导致窗体无法移动.下面提供几种移动方法: 1.采用欺骗的方式.即当鼠标点击客户区的时候,我们欺骗windows ...

  8. Qt Quick无边框窗口

    开发环境:Qt Creator 5.6 内容:  使用 Qt  Quick创建无边框窗口 Qt Quick是一个无比强大.无比方便快捷的跨平台的开发框架,并且能通过Qt强大的元对象系统实现qml与c+ ...

  9. 如何完美的将对话框设置成无边框无标题栏样式?

    很多同学在绘制UI时喜欢将窗口或者对话框设置成无边框无标题栏样式,然后在客户区里就可以"胡作非为"了,想干什么都行 然而新手们包括笔者以前都遇到的一个问题是:对于对话框来说直接这样 ...

最新文章

  1. redis的两种持久化方式详解
  2. 输出9*9口诀python-Python输出9*9乘法表的方法
  3. 如何估算大型项目的工作量
  4. SAP云平台里的日志系统概述
  5. C# 11 预览,又增加了实用的语法糖
  6. 网站需要密码登录访问php源码
  7. 想在研发群里装?先学会这几个排查K8s问题的办法
  8. python - 机器学习lightgbm相关实践
  9. dl388g8 惠普 linux 网卡驱动,hp dl388 gen9驱动下载
  10. 华为odjava机试题_华为机试题及答案
  11. 高斯-拉格朗日(Gauss-Legendre )Ⅱ型求积公式 数值分析 勘误 P111
  12. 前端小白的挖坑填坑之路。
  13. 英特尔处理器全部系列
  14. 毕业设计 - 天气数据分析
  15. C++ Qt 实现小游戏2048
  16. 叒一次算法作业hhhhhhhh
  17. 基于32feet.net对Broadcom(Widcomm)蓝牙开发
  18. cobalt strike profile
  19. VUE项目中安装和使用vant组件
  20. 普通人利用寒假一个月可以学会的四个赚钱技能

热门文章

  1. 阿里云数据库开源发布:PolarDB HTAP的功能特性和关键技术
  2. 为余势负天工背,云原生内存数据库Tair助力用户体验优化
  3. 蚂蚁金服自研分布式关系数据库OceanBase上线阿里云
  4. 用Flink取代Spark Streaming!知乎实时数仓架构演进
  5. 一文了解阿里云CDN HTTP2.0
  6. 第三代英特尔至强可扩展处理器,英特尔数据中心的“芯法宝”
  7. Mendix入局中国低代码,开发者们你准备好了吗
  8. 小网站的容器化(下):网站容器化的各种姿势,先跟着撸一波代码再说!
  9. Cloud一分钟 |亚马逊市值被微软反超;GKE全球大宕机长达19小时;苹果市值跌破9000亿美元...
  10. 如果有这样一台服务器……