[Qt]FrameLessWindow实现调整大小

news/2025/1/14 22:31:16/

说明

我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);后无法移动和调整大小,但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小需求,以此类推,移动窗口也就很简单了(这里没有实现)。
并且这里,还实现了QWidget的窗口阴影,因为FramelessWindow也没有窗口阴影。

代码

#ifndef SHADOWWIDGET_H
#define SHADOWWIDGET_H#include <QWidget>enum MouseDirection {DirectionLeft,DirectionRight,DirectionTop,DirectionBottom,DirectionTopLeft,DirectionTopRight,DirectionBottomLeft,DirectionBottomRight
};class ShadowWidget : public QWidget
{Q_OBJECT
public:explicit ShadowWidget(QWidget *parent = nullptr, QWidget *subWidget = nullptr);protected:bool event(QEvent *event) override;void paintEvent(QPaintEvent *event) override;void resizeEvent(QResizeEvent *event) override;void mousePressEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;
//    void mouseMoveEvent(QMouseEvent *event) override;void responseHoverMoveEvent(QHoverEvent *event);signals:public:uint32_t m_shadowWidthMargin;uint32_t m_shadowHeightMargin;uint32_t m_minWidth;uint32_t m_minHeight;uint32_t m_maxWidth;uint32_t m_maxHeight;QWidget *m_subWidget;private:QPixmap m_shadowPixmap;bool m_bCanDrag;bool m_bMousePress;QPoint m_globalPointPressed;QRect m_geoPressed;MouseDirection m_curMousePressMoveDirection;
};#endif // SHADOWWIDGET_H
#include "shadowwidget.h"#include <QPainter>
#include <QResizeEvent>
#include <QApplication>
#include <QScreen>
#include <QDebug>static QPixmap ninePatchScalePixmap(QPixmap *pix, int iHorzSplit, int iVertSplit, int DstWidth, int DstHeight)// 参考[1]
{int pixWidth = pix->width();int pixHeight = pix->height();QPixmap pix_1 = pix->copy(0, 0, iHorzSplit, iVertSplit);QPixmap pix_2 = pix->copy(iHorzSplit, 0, pixWidth - iHorzSplit * 2, iVertSplit);QPixmap pix_3 = pix->copy(pixWidth - iHorzSplit, 0, iHorzSplit, iVertSplit);QPixmap pix_4 = pix->copy(0, iVertSplit, iHorzSplit, pixHeight - iVertSplit * 2);QPixmap pix_5 = pix->copy(iHorzSplit, iVertSplit, pixWidth - iHorzSplit * 2, pixHeight - iVertSplit * 2);QPixmap pix_6 = pix->copy(pixWidth - iHorzSplit, iVertSplit, iHorzSplit, pixHeight - iVertSplit * 2);QPixmap pix_7 = pix->copy(0, pixHeight - iVertSplit, iHorzSplit, iVertSplit);QPixmap pix_8 = pix->copy(iHorzSplit, pixHeight - iVertSplit, pixWidth - iHorzSplit * 2, pixWidth - iHorzSplit * 2);QPixmap pix_9 = pix->copy(pixWidth - iHorzSplit, pixHeight - iVertSplit, iHorzSplit, iVertSplit);pix_2 = pix_2.scaled(DstWidth - iHorzSplit * 2, iVertSplit, Qt::IgnoreAspectRatio);//保持高度拉宽;pix_4 = pix_4.scaled(iHorzSplit, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//保持宽度拉高;pix_5 = pix_5.scaled(DstWidth - iHorzSplit * 2, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//宽高都缩放;pix_6 = pix_6.scaled(iHorzSplit, DstHeight - iVertSplit * 2, Qt::IgnoreAspectRatio);//保持宽度拉高;pix_8 = pix_8.scaled(DstWidth - iHorzSplit * 2, iVertSplit);//保持高度拉宽;QPixmap resultImg(DstWidth, DstHeight);// 需设置背景透明;resultImg.fill(Qt::transparent);QPainter* painter = new QPainter(&resultImg);if (!resultImg.isNull()) {painter->drawPixmap(0, 0, pix_1);painter->drawPixmap(iHorzSplit, 0, pix_2);painter->drawPixmap(DstWidth - iHorzSplit, 0, pix_3);painter->drawPixmap(0, iVertSplit, pix_4);painter->drawPixmap(iHorzSplit, iVertSplit, pix_5);painter->drawPixmap(DstWidth - iHorzSplit, iVertSplit, pix_6);painter->drawPixmap(0, DstHeight - iVertSplit, pix_7);painter->drawPixmap(iHorzSplit, DstHeight - iVertSplit, pix_8);painter->drawPixmap(DstWidth - iHorzSplit, DstHeight - iVertSplit, pix_9);painter->end();}return resultImg;
}ShadowWidget::ShadowWidget(QWidget *parent, QWidget *subWidget) :QWidget(parent),m_shadowWidthMargin(5),m_shadowHeightMargin(5),m_subWidget(subWidget),m_shadowPixmap(":resource/shadow.png"),m_bCanDrag(false),m_bMousePress(false),m_globalPointPressed(QPoint()),m_minWidth(120),m_minHeight(120),m_maxWidth(INT32_MAX),m_maxHeight(INT32_MAX)
{this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);this->setAttribute(Qt::WA_TranslucentBackground, true);this->setAttribute(Qt::WA_Hover, true); // 开启Hover事件记录,替代mouseMoveEvent,但CPU代价更高
}bool ShadowWidget::event(QEvent *event)
{if (QEvent::HoverMove == event->type()){QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);this->responseHoverMoveEvent(hoverEvent);event->accept();return true;}return QWidget::event(event);
}void ShadowWidget::paintEvent(QPaintEvent *event)
{QWidget::paintEvent(event);QPainter painter(this);painter.drawPixmap(this->rect(), m_shadowPixmap);
}void ShadowWidget::resizeEvent(QResizeEvent *event)
{// 重新生成geometry()大小的图片m_shadowPixmap = ::ninePatchScalePixmap(&m_shadowPixmap, 10, 10,event->size().width(), event->size().height());// 重置subWidget大小if (m_subWidget){QRect rect;rect.setTopLeft(QPoint(m_shadowWidthMargin, m_shadowWidthMargin));rect.setSize(QSize(this->geometry().width() - 2 * m_shadowWidthMargin,this->geometry().height() - 2 * m_shadowHeightMargin));m_subWidget->setGeometry(rect);}QWidget::resizeEvent(event);this->repaint();
}void ShadowWidget::mousePressEvent(QMouseEvent *event)
{if (m_bCanDrag){m_bMousePress = true;m_globalPointPressed = event->globalPos();m_geoPressed = this->geometry();}return QWidget::mousePressEvent(event);
}void ShadowWidget::mouseReleaseEvent(QMouseEvent *event)
{m_bMousePress = false;m_globalPointPressed = QPoint();m_geoPressed = QRect();return QWidget::mouseReleaseEvent(event);
}void ShadowWidget::responseHoverMoveEvent(QHoverEvent *event)
{QPoint pt = event->pos();// 可拖拽区域鼠标拖拽,调整窗口大小if (m_bMousePress){QPoint globalPt = QPoint(this->x() + pt.x(), this->y() + pt.y());double xDiff = globalPt.x() - m_globalPointPressed.x();double yDiff = globalPt.y() - m_globalPointPressed.y();QRect rect = m_geoPressed;if (m_curMousePressMoveDirection == DirectionLeft)rect.setX(rect.x() + xDiff);else if (m_curMousePressMoveDirection == DirectionRight)rect.setWidth(rect.width() + xDiff);else if (m_curMousePressMoveDirection == DirectionTop)rect.setY(rect.y() + yDiff);else if (m_curMousePressMoveDirection == DirectionBottom)rect.setHeight(rect.height() + yDiff);else if (m_curMousePressMoveDirection == DirectionTopLeft){rect.setX(rect.x() + xDiff);rect.setY(rect.y() + yDiff);}else if (m_curMousePressMoveDirection == DirectionTopRight){rect.setY(rect.y() + yDiff);rect.setWidth(rect.width() + xDiff);}else if (m_curMousePressMoveDirection == DirectionBottomLeft){rect.setHeight(rect.height() + yDiff);rect.setX(rect.x() + xDiff);}else if (m_curMousePressMoveDirection == DirectionBottomRight){rect.setHeight(rect.height() + yDiff);rect.setWidth(rect.width() + xDiff);}rect.setWidth(qMax<int>(qMin<int>(m_maxWidth, rect.width()), m_minWidth));rect.setHeight(qMax<int>(qMin<int>(m_maxHeight, rect.height()), m_minHeight));this->setGeometry(rect);return;}// 若鼠标在subWidget中则重置鼠标QRect subWidgetCannotDragRect = m_subWidget->geometry().adjusted(m_shadowWidthMargin,m_shadowHeightMargin,-m_shadowWidthMargin,-m_shadowHeightMargin);if (subWidgetCannotDragRect.contains(pt)){m_bCanDrag = false;QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));return;}m_bCanDrag = true;// 根据当前鼠标位置确定应该选择那种伸缩图标MouseDirection direction;if (pt.x() < 2 * m_shadowWidthMargin){direction = DirectionLeft;if (pt.y() < 2 * m_shadowHeightMargin)direction = DirectionTopLeft;else if ((this->height() - pt.y()) < 2 * m_shadowHeightMargin)direction = DirectionBottomLeft;}else if ((this->width() - pt.x()) < 2 * m_shadowWidthMargin){direction = DirectionRight;if (pt.y() < 2 * m_shadowHeightMargin)direction = DirectionTopRight;else if ((this->height() - pt.y()) < 2 * m_shadowHeightMargin)direction = DirectionBottomRight;}else if (pt.y() < 2 * m_shadowHeightMargin){direction = DirectionTop;if (pt.x() < 2 * m_shadowWidthMargin)direction = DirectionTopLeft;else if ((this->width() - pt.x()) < 2 * m_shadowWidthMargin)direction = DirectionTopRight;}else if ((this->height() - pt.y()) < 2 * m_shadowHeightMargin){direction = DirectionBottom;if (pt.x() < 2 * m_shadowWidthMargin)direction = DirectionBottomLeft;else if ((this->width() - pt.x()) < 2 * m_shadowWidthMargin)direction = DirectionBottomRight;}m_curMousePressMoveDirection = direction;switch (direction){case DirectionLeft:case DirectionRight:QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));break;case DirectionTop:case DirectionBottom:QApplication::setOverrideCursor(QCursor(Qt::SizeVerCursor));break;case DirectionTopLeft:case DirectionBottomRight:QApplication::setOverrideCursor(QCursor(Qt::SizeFDiagCursor));break;case DirectionTopRight:case DirectionBottomLeft:QApplication::setOverrideCursor(QCursor(Qt::SizeBDiagCursor));break;}
}

解释

  • m_minWidth、m_minHeight、m_maxWidth、m_maxHeight:防止窗口太大或太小。
  • m_shadowWidthMargin、m_shadowHeightMargin:记录窗口阴影的宽和高。
  • m_subWidget:用于中间放置主Widget(阴影弹窗作为后面的一个widget)。
  • m_shadowPixmap:阴影图。
  • m_bCanDrag:记录是否可调整大小。
  • m_bMousePress:记录是否在可调整大小的情况下,鼠标按下了。
  • m_globalPointPressed:用于记录按下时的全局坐标点。
  • m_geoPressed:记录按下时,阴影窗口的geometry。
  • m_curMousePressMoveDirection:记录拖拽方向。
  • enum MouseDirection:标记窗口方向,共有8个方向。

参考:
1


http://www.ppmy.cn/news/1001951.html

相关文章

分布式框架dubbo

1.分布式系统相关概念 1.1基本概念 1.2 集群和分布式 1.3 架构演进 A是一个微服务。ADB是一个组件。A可以java&#xff0c;B可以python实现。 2 dubbo 2.1 概述 2.2 dubbo代码 2.2.1 服务提供者的改造-将项目service层对外发布到dubbo 通过dubbo中的service注解&#xff…

学无止境·运维高阶③(Mysqldump脚本)

Mysqldump脚本 1、详细脚本2、执行 1、详细脚本 #!/bin/bash mysql_cmd‘-uroot -pRedHat123’ exclude_db‘information_schema|performance_schema|sys’ bak_path/backup/db mysql m y s q l c m d − e ′ s h o w d a t a b a s e s ′ − N ∣ e g r e p − v " {m…

2023年08月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年08月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

Python——调用webdriver.Chrome() 报错

今天运行脚本&#xff0c;报错内容如下&#xff1a; collecting ... login_case.py:None (login_case.py) login_case.py:11: in <module> dr webdriver.Chrome() D:\Program Files (x86)\Python\Python39\Lib\site-packages\selenium\webdriver\chrome\webdriver.p…

MYSQL进阶-事务

什么是数据库事务&#xff1f; 事务是一个不可分割的数据库操作序列&#xff0c;也是数据库并发控制的基本单位&#xff0c;其执 行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上 的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务最…

2023华数杯数学建模A题思路分析 - 隔热材料的结构优化控制研究

# 1 赛题 A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性&#xff0c;在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前&#xff0c;由单根隔热材料 A 纤维编织成的织物&#xff0c;其热导率可以直接测出&#xff1b;但是 单根隔热…

小白如何获取CNVD事件型原创漏洞证明?——记CNVD漏洞挖掘思路

引子: 相信许多人都想要被别人叫做大佬&#xff0c;漏洞挖掘当中肯定也不例外,所以在此之前让我们康康度娘对大佬的定义:形容一个人很巨表示对其顶礼膜拜的态度。在这种情况下&#xff0c; 国家信息安全漏洞共享平台(CNVD) 则为我们提供了一个成为大佬的平台, CNVD作为国内最具…

负数的二进制转换成十进制

对于一个k位的二进制正数&#xff0c;其表示成十进制的结果是&#xff1a; pos[i]表示&#xff1a;这个正数的二进制形式的第i位是1。 i从最低位&#xff08;第0位&#xff09;开始&#xff0c;一直到k-1位。有符号数中&#xff0c;正数的第k-1为0&#xff0c;负数的第k-1位为…