1、原理
2、代码

1 void MyWidget::mouseMoveEvent(QMouseEvent *event) 2 { 3 QPoint P3 = event->globalPos(); 4 QPoint P2 = P3 - L; 5 this->move(P2); 6 } 7 8 void MyWidget::mousePressEvent(QMouseEvent *event) 9 { 10 QPoint P3 = event->globalPos(); 11 QPoint P2 = this->geometry().topLeft(); 12 L = P3 - P2; // L是QPoint变量,在.h文件中创建 13 } 14 15 void MyWidget::mouseReleaseEvent(QMouseEvent *) 16 { 17 this->L = QPoint(); 18 }
3、展示
/*************************************************************************************/
2020-11-12更新升级版
.h文件

1 private: 2 void paintMoveRect(QMouseEvent *e); 3 void mousePressEvent(QMouseEvent *e)override; 4 void mouseMoveEvent(QMouseEvent *e)override; 5 void mouseReleaseEvent(QMouseEvent *e)override; 6 7 private: 8 Ui::MainWindow *ui; 9 QWidget *w; // 预览窗口 10 QPoint L = QPoint(); 11 QPoint P2 = QPoint(); 12 QPoint P3 = QPoint(); 13 bool moveFlag = false;
.cpp文件
PS:采用的是无边框窗口,所以标题栏是自己拉的widget。

1 void MainWindow::paintMoveRect(QMouseEvent * e) 2 { 3 QSize size= this->size(); 4 w = new QWidget(); 5 w->resize(size); 6 w->setWindowFlag(Qt::FramelessWindowHint); 7 w->setWindowOpacity(0.5); 8 w->setStyleSheet("background-color: rgb(160, 188, 255);"); 9 10 w->move(this->pos()); 11 w->show(); 12 13 P3 = e->globalPos(); 14 P2 = w->geometry().topLeft(); 15 L = P3 - P2; 16 } 17 18 void MainWindow::mousePressEvent(QMouseEvent *e) 19 { 20 if(e->button() == Qt::LeftButton) 21 { 22 // 判断鼠标选中是否为标题栏 23 if(ui->widget == this->findChild<QWidget*>("widget")) 24 { 25 moveFlag = true; 26 paintMoveRect(e); 27 } 28 } 29 e->accept(); 30 } 31 32 void MainWindow::mouseMoveEvent(QMouseEvent *e) 33 { 34 if(moveFlag) 35 { 36 P3 = e->globalPos(); 37 P2 = P3 - L; 38 w->move(P2); 39 e->accept(); 40 } 41 e->accept(); 42 } 43 44 void MainWindow::mouseReleaseEvent(QMouseEvent *e) 45 { 46 if(moveFlag) 47 { 48 this->move(P2); 49 delete w; 50 w = nullptr; 51 moveFlag = false; 52 } 53 e->accept(); 54 }
预览gif
/*************************************************************************************/
2020-11-13更新(参考:https://blog.csdn.net/GoForwardToStep/article/details/77887777)
画了一个简单的示意图,其实窗口拉伸也就这8块区域,当鼠标移动进入这8块区域时,需要判断当前进入了哪一块区域,然后显示什么样式。

1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include<QDebug> 6 7 QT_BEGIN_NAMESPACE 8 namespace Ui { class MainWindow; } 9 QT_END_NAMESPACE 10 11 class MainWindow : public QMainWindow 12 { 13 Q_OBJECT 14 15 private: 16 // 鼠标状态枚举 17 enum mousePositionState 18 { 19 NO_SELECT = 0, 20 LEFT_TOP_RECT, 21 TOP_BORDER, 22 RIGHT_TOP_RECT, 23 RIGHT_BORDER, 24 RIGHT_BOTTOM_RECT, 25 BOTTOM_BORDER, 26 LEFT_BOTTOM_RECT, 27 LEFT_BORDER 28 }; 29 30 public: 31 MainWindow(QWidget *parent = nullptr); 32 ~MainWindow(); 33 34 private slots: 35 void on_pushButton_clicked(); 36 37 void on_pushButton_3_clicked(); 38 39 void on_pushButton_4_clicked(); 40 41 private: 42 void paintMoveRect(QMouseEvent *e); 43 void mousePressEvent(QMouseEvent *e)override; 44 void mouseMoveEvent(QMouseEvent *e)override; 45 void mouseReleaseEvent(QMouseEvent *e)override; 46 bool event(QEvent *event) override; 47 48 void calculateWindow(); // 计算8个Rect,每次拉伸都调用重新计算 49 mousePositionState getCursorState(QPoint pos); // 获取鼠标状态 50 void updateMouseStyle(mousePositionState mouseState); // 更新鼠标状态 51 void updateSize(); // 更新窗口尺寸 52 53 private: 54 Ui::MainWindow *ui; 55 QWidget *w; // 预览窗口 56 QPoint L = QPoint(); 57 QPoint P2 = QPoint(); 58 QPoint P3 = QPoint(); 59 bool moveFlag = false; 60 61 QRect m_leftTopRect; 62 QRect m_leftBottomRect; 63 QRect m_rightTopRect; 64 QRect m_rightBottomRect; 65 66 QRect m_topBorderRect; 67 QRect m_rightBorderRect; 68 QRect m_bottomBorderRect; 69 QRect m_leftBorderRect; 70 71 mousePositionState m_cursorState = NO_SELECT; 72 QPoint m_startPoint; // 拉伸前的点 73 QPoint m_endPoint; // 拉伸后的点 74 QRect m_beforSize; // 鼠标按下事件之前的窗口尺寸 75 bool m_mousePressed = false; // 鼠标按下状态 76 int m_minWidth; // 原始窗口宽度 77 int m_minHeight; // 原始窗口高度 78 }; 79 80 #endif // MAINWINDOW_H

#include "mainwindow.h" #include "ui_mainwindow.h" #include <QHoverEvent> #include <QMouseEvent> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); this->setWindowFlag(Qt::FramelessWindowHint); this->setAttribute(Qt::WA_Hover, true); m_minWidth = this->size().width(); // 保存原始窗口宽度 m_minHeight = this->size().height(); // 保存原始窗口高度 calculateWindow(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::paintMoveRect(QMouseEvent * e) { QSize size= this->size(); w = new QWidget(); w->resize(size); w->setWindowFlag(Qt::FramelessWindowHint); w->setWindowOpacity(0.5); w->setStyleSheet("background-color: rgb(160, 188, 255);"); w->move(this->pos()); w->show(); P3 = e->globalPos(); P2 = w->geometry().topLeft(); L = P3 - P2; } void MainWindow::mousePressEvent(QMouseEvent *e) { if(m_cursorState !=NO_SELECT && e->button() == Qt::LeftButton) { m_mousePressed = true; m_startPoint = this->mapToGlobal(e->pos()); m_beforSize = this->geometry(); e->accept(); } if(m_cursorState ==NO_SELECT && e->button() == Qt::LeftButton) { // 判断鼠标选中是否为标题栏 if(ui->widget == this->findChild<QWidget*>("widget")) { // 窗口最大化时候不能移动 if(this->windowState() != (Qt::WindowMaximized | Qt::WindowFullScreen) && this->windowState() != Qt::WindowMaximized) { moveFlag = true; paintMoveRect(e); } } e->accept(); } } void MainWindow::mouseMoveEvent(QMouseEvent *e) { if(moveFlag) { P3 = e->globalPos(); P2 = P3 - L; w->move(P2); e->accept(); } } void MainWindow::mouseReleaseEvent(QMouseEvent *e) { if(moveFlag) { this->move(P2); delete w; w = nullptr; moveFlag = false; e->accept(); } m_mousePressed = false; calculateWindow(); } bool MainWindow::event(QEvent *event) { if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave || event->type() == QEvent::HoverMove) { QHoverEvent* pHoverEvent = static_cast<QHoverEvent*>(event); QPoint cursorPos = pHoverEvent->pos(); if(!m_mousePressed) { // 最大化时无法拉伸 if(this->windowState() != (Qt::WindowMaximized | Qt::WindowFullScreen) && this->windowState() != Qt::WindowMaximized) { // 根据当前鼠标的位置显示不同的样式; m_cursorState = getCursorState(cursorPos); updateMouseStyle(m_cursorState); } } else { m_endPoint = this->mapToGlobal(cursorPos); updateSize(); } } return QWidget::event(event); } void MainWindow::calculateWindow() { // 4个角Rect m_leftTopRect = QRect(0, 0, 4, 4); m_leftBottomRect = QRect(0, this->height() - 4, 4, 4); m_rightTopRect = QRect(this->width() - 4, 0, 4 , 4); m_rightBottomRect = QRect(this->width() - 4, this->height() - 4, 4, 4); // 4条边Rect m_topBorderRect = QRect(4, 0, this->width() - 8, 4); m_rightBorderRect = QRect(this->width() - 4, 4, 4, this->height() - 8); m_bottomBorderRect = QRect(4, this->height() - 4, this->width() - 8, 4); m_leftBorderRect = QRect(0, 4, 4, this->height() - 8); } MainWindow::mousePositionState MainWindow::getCursorState(QPoint pos) { mousePositionState mouseState; if(m_leftTopRect.contains(pos)) mouseState = LEFT_TOP_RECT; else if(m_rightTopRect.contains(pos)) mouseState = RIGHT_TOP_RECT; else if(m_rightBottomRect.contains(pos)) mouseState = RIGHT_BOTTOM_RECT; else if(m_leftBottomRect.contains(pos)) mouseState = LEFT_BOTTOM_RECT; else if(m_topBorderRect.contains(pos)) mouseState = TOP_BORDER; else if(m_bottomBorderRect.contains(pos)) mouseState = BOTTOM_BORDER; else if(m_leftBorderRect.contains(pos)) mouseState = LEFT_BORDER; else if(m_rightBorderRect.contains(pos)) mouseState = RIGHT_BORDER; else mouseState = NO_SELECT; return mouseState; } void MainWindow::updateMouseStyle(MainWindow::mousePositionState mouseState) { switch (mouseState) { case NO_SELECT: this->setCursor(Qt::ArrowCursor); break; case LEFT_TOP_RECT: case RIGHT_BOTTOM_RECT: this->setCursor(Qt::SizeFDiagCursor); break; case TOP_BORDER: case BOTTOM_BORDER: this->setCursor(Qt::SizeVerCursor); break; case RIGHT_TOP_RECT: case LEFT_BOTTOM_RECT: setCursor(Qt::SizeBDiagCursor); break; case LEFT_BORDER: case RIGHT_BORDER: setCursor(Qt::SizeHorCursor); break; default: setCursor(Qt::ArrowCursor); break; } } void MainWindow::updateSize() { // 更新窗口尺寸 QRect windowRect = m_beforSize; int delValue_X = m_startPoint.x() - m_endPoint.x(); int delValue_Y = m_startPoint.y() - m_endPoint.y(); if (m_cursorState == LEFT_BORDER) { QPoint topLeftPoint = windowRect.topLeft(); topLeftPoint.setX(topLeftPoint.x() - delValue_X); windowRect.setTopLeft(topLeftPoint); } else if (m_cursorState == RIGHT_BORDER) { QPoint bottomRightPoint = windowRect.bottomRight(); bottomRightPoint.setX(bottomRightPoint.x() - delValue_X); windowRect.setBottomRight(bottomRightPoint); } else if (m_cursorState == TOP_BORDER) { QPoint topLeftPoint = windowRect.topLeft(); topLeftPoint.setY(topLeftPoint.y() - delValue_Y); windowRect.setTopLeft(topLeftPoint); } else if (m_cursorState == BOTTOM_BORDER) { QPoint bottomRightPoint = windowRect.bottomRight(); bottomRightPoint.setY(bottomRightPoint.y() - delValue_Y); windowRect.setBottomRight(bottomRightPoint); } else if (m_cursorState == LEFT_TOP_RECT) { QPoint topLeftPoint = windowRect.topLeft(); topLeftPoint.setX(topLeftPoint.x() - delValue_X); topLeftPoint.setY(topLeftPoint.y() - delValue_Y); windowRect.setTopLeft(topLeftPoint); } else if (m_cursorState == RIGHT_TOP_RECT) { QPoint topRightPoint = windowRect.topRight(); topRightPoint.setX(topRightPoint.x() - delValue_X); topRightPoint.setY(topRightPoint.y() - delValue_Y); windowRect.setTopRight(topRightPoint); } else if (m_cursorState == RIGHT_BOTTOM_RECT) { QPoint bottomRightPoint = windowRect.bottomRight(); bottomRightPoint.setX(bottomRightPoint.x() - delValue_X); bottomRightPoint.setY(bottomRightPoint.y() - delValue_Y); windowRect.setBottomRight(bottomRightPoint); } else if (m_cursorState == LEFT_BOTTOM_RECT) { QPoint bottomLeftPoint = windowRect.bottomLeft(); bottomLeftPoint.setX(bottomLeftPoint.x() - delValue_X); bottomLeftPoint.setY(bottomLeftPoint.y() - delValue_Y); windowRect.setBottomLeft(bottomLeftPoint); } if(windowRect.width() < m_minWidth) { windowRect.setLeft(this->geometry().left()); windowRect.setWidth(m_minWidth); } if (windowRect.height() < m_minHeight) { windowRect.setTop(this->geometry().top()); windowRect.setHeight(m_minHeight); } this->setGeometry(windowRect); }
不知道为什么拉伸的时候,右边有点掉帧。。。。。