Qt开源作品16-通用无边框拖动拉伸
一、前言
相信各位CS结构开发的程序员,多多少少都遇到过需要美化界面的事情,一般都不会采用系统的标题栏,这样就需要无边框标题栏窗体,默认的话无边框的标题栏都不支持拉伸和拖动的,毕竟去掉了标题栏则意味着失去了系统的窗体的属性,拉伸和拖动都需要自己写代码去实现,网上有很多类似的开源的方案,我也看过不少,总体来说复杂了些,对于初学者来说有可能看的云里雾里的,比如边框四周八个方位都可以自由拉伸这块,我的思路是针对设定的八个方位的区域进行识别鼠标是否按下,按下的哪个部位则执行什么拉伸策略,鼠标移到哪个位置则对应改变鼠标指针形状,更浅显易懂一些,至于拖动移动,还可以设置拖动的标题栏的高度等。
主要功能:
- 可以指定需要无边框的widget
- 边框四周八个方位都可以自由拉伸
- 可设置对应位置的边距,以便识别更大区域
- 可设置是否允许拖动
- 可设置是否允许拉伸
二、代码思路
bool FramelessWidget::eventFilter(QObject *watched, QEvent *event)
{
if (widget != 0 && watched == widget) {
if (event->type() == QEvent::Resize) {
//重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内
int width = widget->width();
int height = widget->height();
//左侧描点区域
rectLeft = QRect(0, padding, padding, height - padding * 2);
//上侧描点区域
rectTop = QRect(padding, 0, width - padding * 2, padding);
//右侧描点区域
rectRight = QRect(width - padding, padding, padding, height - padding * 2);
//下侧描点区域
rectBottom = QRect(padding, height - padding, width - padding * 2, padding);
//左上角描点区域
rectLeftTop = QRect(0, 0, padding, padding);
//右上角描点区域
rectRightTop = QRect(width - padding, 0, padding, padding);
//左下角描点区域
rectLeftBottom = QRect(0, height - padding, padding, padding);
//右下角描点区域
rectRightBottom = QRect(width - padding, height - padding, padding, padding);
} else if (event->type() == QEvent::HoverMove) {
//设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别
QHoverEvent *hoverEvent = (QHoverEvent *)event;
QPoint point = hoverEvent->pos();
if (resizeEnable) {
if (rectLeft.contains(point)) {
widget->setCursor(Qt::SizeHorCursor);
} else if (rectRight.contains(point)) {
widget->setCursor(Qt::SizeHorCursor);
} else if (rectTop.contains(point)) {
widget->setCursor(Qt::SizeVerCursor);
} else if (rectBottom.contains(point)) {
widget->setCursor(Qt::SizeVerCursor);
} else if (rectLeftTop.contains(point)) {
widget->setCursor(Qt::SizeFDiagCursor);
} else if (rectRightTop.contains(point)) {
widget->setCursor(Qt::SizeBDiagCursor);
} else if (rectLeftBottom.contains(point)) {
widget->setCursor(Qt::SizeBDiagCursor);
} else if (rectRightBottom.contains(point)) {
widget->setCursor(Qt::SizeFDiagCursor);
} else {
widget->setCursor(Qt::ArrowCursor);
}
}
//根据当前鼠标位置,计算XY轴移动了多少
int offsetX = point.x() - lastPos.x();
int offsetY = point.y() - lastPos.y();
//根据按下处的位置判断是否是移动控件还是拉伸控件
if (moveEnable) {
if (pressed) {
widget->move(widget->x() + offsetX, widget->y() + offsetY);
}
}
if (resizeEnable) {
if (pressedLeft) {
int resizeW = widget->width() - offsetX;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, rectY, resizeW, rectH);
}
} else if (pressedRight) {
widget->setGeometry(rectX, rectY, rectW + offsetX, rectH);
} else if (pressedTop) {
int resizeH = widget->height() - offsetY;
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(rectX, widget->y() + offsetY, rectW, resizeH);
}
} else if (pressedBottom) {
widget->setGeometry(rectX, rectY, rectW, rectH + offsetY);
} else if (pressedLeftTop) {
int resizeW = widget->width() - offsetX;
int resizeH = widget->height() - offsetY;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
}
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
}
} else if (pressedRightTop) {
int resizeW = rectW + offsetX;
int resizeH = widget->height() - offsetY;
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH);
}
} else if (pressedLeftBottom) {
int resizeW = widget->width() - offsetX;
int resizeH = rectH + offsetY;
if (widget->minimumWidth() <= resizeW) {
widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH);
}
if (widget->minimumHeight() <= resizeH) {
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
}
} else if (pressedRightBottom) {
int resizeW = rectW + offsetX;
int resizeH = rectH + offsetY;
widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
//记住当前控件坐标和宽高以及鼠标按下的坐标
QMouseEvent *mouseEvent = (QMouseEvent *)event;
rectX = widget->x();
rectY = widget->y();
rectW = widget->width();
rectH = widget->height();
lastPos = mouseEvent->pos();
//判断按下的手柄的区域位置
if (rectLeft.contains(lastPos)) {
pressedLeft = true;
} else if (rectRight.contains(lastPos)) {
pressedRight = true;
} else if (rectTop.contains(lastPos)) {
pressedTop = true;
} else if (rectBottom.contains(lastPos)) {
pressedBottom = true;
} else if (rectLeftTop.contains(lastPos)) {
pressedLeftTop = true;
} else if (rectRightTop.contains(lastPos)) {
pressedRightTop = true;
} else if (rectLeftBottom.contains(lastPos)) {
pressedLeftBottom = true;
} else if (rectRightBottom.contains(lastPos)) {
pressedRightBottom = true;
} else {
pressed = true;
}
} else if (event->type() == QEvent::MouseMove) {
//改成用HoverMove识别
} else if (event->type() == QEvent::MouseButtonRelease) {
//恢复所有
pressed = false;
pressedLeft = false;
pressedRight = false;
pressedTop = false;
pressedBottom = false;
pressedLeftTop = false;
pressedRightTop = false;
pressedLeftBottom = false;
pressedRightBottom = false;
widget->setCursor(Qt::ArrowCursor);
}
}
return QObject::eventFilter(watched, event);
}
三、效果图

四、开源主页
- 以上作品完整源码下载都在开源主页,会持续不断更新作品数量和质量,欢迎各位关注。
- 本开源项目已经成功升级到V2.0版本,分门别类,图文并茂,保你爽到爆。
- Qt开源武林秘籍开发经验,看完学完,20K起薪,没有找我!
- 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
- 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
- 开源秘籍:https://gitee.com/feiyangqingyun/qtkaifajingyan
- 个人主页:https://qtchina.blog.csdn.net/
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
Qt开源作品16-通用无边框拖动拉伸的更多相关文章
- Qt开源作品38-无边框窗体方案(无抖动,支持win、linux、mac等系统,侧边半屏顶部全屏)
一 前言 不知道各位程序员有没有遇到过这样一种困惑,好不容易在开源网站找到了类似的想要的项目代码,结果down下来一编译,我勒个去,几百个错误,根本没法用,熟悉的人还好可以直接阅读代码进行修改(有些只 ...
- WPF无边框拖动、全屏、缩放
原文:WPF无边框拖动.全屏.缩放 版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/lwwl12/article/details/78059361 先看效果 ...
- winform学习(9)无边框拖动窗体
去除边框 选中窗体,在属性中找到FormBorderStyle,设置为None 实现无边框拖动 [DllImport("user32.dll")] public st ...
- Qt编写自定义控件67-通用无边框
一.前言 在之前的一篇文章中写过一个通用的移动控件,作用就是用来传入任意的widget控件,可以在父类容器中自由移动.本篇文章要写的是一个通用的无边框类,确切的说这不叫控件应该叫组件才对,控件是要看得 ...
- qt 5 小练习 创建无边框界面
我们大家都知道QT5 自带的界面不是那么美观,并且每个软件我们都发现他们的边框是自定义的,所以我决定写一篇这样的博文,也许已经有许许多多篇大牛写的论文了,但我还是想写一篇记录自己的学习QT的历程 首先 ...
- 【Qt】Qt之自定义界面(实现无边框、可移动)【转】
简述 UI设计是指对软件的人机交互.操作逻辑.界面美观的整体设计.好的UI设计不仅是让软件变得有个性.有品位,还要让软件的操作变得舒适简单.自由,充分体现软件的定位和特点. 爱美之心人皆有之.其实软件 ...
- Qt之自定义界面(实现无边框、可移动)
简述 UI设计是指对软件的人机交互.操作逻辑.界面美观的整体设计.好的UI设计不仅是让软件变得有个性.有品位,还要让软件的操作变得舒适简单.自由,充分体现软件的定位和特点. 爱美之心人皆有之.其实软件 ...
- WPF 无边框拖动
无边框之后的拖动方法有三种. 我个人是喜欢第一和第三的方法,看个人去需求. 第三种代码比较仓促,有需要者可以立马用,或者稍作整理修改. 对于WIN10 .NET 4.5以上的框架可以使用 WIndow ...
- pyqt5无边框拖动
from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys class ...
- CreateWindow创建无边框 可拉伸窗体
createwindow 定义 HWND WINAPI CreateWindow( _In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowNam ...
随机推荐
- KubeKey v3.1 发布:快速自定义离线安装包
日前,KubeKey v3.1 正式发布.该版本主要对离线场景部署.离线包制作以及向 Kubernetes v1.24+ 升级进行了优化. KubeKey 简介 KubeKey 是 KubeSpher ...
- 写代码被大语言模型坑之使用LocalDateTime比较两个时间差了几天
自从去年ChatGPT3.5发布后使用了几次,现在写代码基本上离不开它和它的衍生产品们了.一方面查资料很方便,快速提炼要点总结:另一方面想写什么样的代码一问就能生成出来,功能大差不差,稍微改改就能用, ...
- Tony Bai · Go语言第一课 _个人笔记 04|初窥门径:一个Go程序的结构是怎样的?
Tony Bai · Go语言第一课 _个人笔记 04|初窥门径:一个Go程序的结构是怎样的? 1.配置国内的Go模块的镜像 配置国内镜像代理(使用阿里云镜像) go env -w GOPROXY=h ...
- 买了个mini主机当服务器
虽然有苹果的电脑,但是在装一些软件的时候,从想着能不能有一个小型的服务器,免得各种设置什么帮我强各种别的导致Mac出现各种的异常,整体上的话去看了一些小的主机,看过苹果的MV迷你Mac,但是发现是太贵 ...
- SSAS部署失败方法总结
最近在自学SSAS,从最简单的入手,却频频遇到问题,为了以后在学习过程中能更快的进行问题的定位,所以在此将遇到的问题以及解决方案进行记录 Q1:数据源"Adventure Works DW2 ...
- DPaRL:耶鲁+AWS出品,开放世界持续学习场景的新解法 | ECCV'24
来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: Open-World Dynamic Prompt and Continual Visual Representation Learning ...
- 使用switch语句的注意事项
目录 case后需要手动break switch内的变量定义 变量没有定义在语句块内 变量定义在语句块内 表述多情况时不能用逗号 case后需要手动break switch(i){ case 1: 语 ...
- php 异步并行后续--兼容FPM使用的组件
上次给人推荐了这篇文章,关于PHP异步并行的文章,之后有人评论问这个组件能不能给fpm用,我测试了一下发现不行,于是又找到一个可以给fpm用的http请求组件. 安装很简单,就这样 composer ...
- Redis未授权漏洞复现
目录 Redis 漏洞的产生条件及利用 Redis环境搭建 漏洞复现 利用Redis写入Webshell 利用Redis写入SSH公钥 利用Redis写入计划任务 Redis安全防护 Redis re ...
- golang之errors包
errors包常用方法 func Unwrap(err error) error // 获得err包含下一层错误 func Is(err, target error) bool // 判断err是否包 ...