Qt 去掉边框 调整窗口宽高最大化最小化 仿 Windows操作窗口操作
去掉边框后想实现控制窗口的基本操作,但网上大多都是实时移动窗口,(比如移动窗口时,左键按下,窗口跟随鼠标实时移动; 不像windows 在移动时先有一个边框移动,当左键松开时实际窗口移动到边框位置)
用边框方式控制窗口尺寸时可以防止窗口频繁重绘控件(resizeEvent、paintEvent)。
封装了一个类QFrameDemo方便控制窗口使用,在末尾有使用示例:
qframedemo.h:
#ifndef QFRAMEDEMO_H #define QFRAMEDEMO_H #include <QFrame> #define padding 10 enum State{ LEFT, RIGHT, TOP, BOTTOM, LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM, NORMAL }; class QFrameDemo : public QFrame { public: QFrameDemo(QWidget *widget); void paintEvent(QPaintEvent *); bool setCursorState(int mouseX, int mouseY); void moveEvent(QMouseEvent *event); void press(QMouseEvent *event); void release(QMouseEvent *event); void flushPos(); private: //画边框时QRect QRect borderRect; //当前鼠标状态 State state; //让那个widget支持调整尺寸 QWidget *widget; //是否左键被按下 bool isPress = false; //左键按下是鼠标X位置,窗口坐上角为0,0 int lastMouseX = 0; //左键按下是鼠标Y位置,窗口坐上角为0,0 int lastMouseY = 0; //窗口在屏幕中X位置 int lastWinX = 0; //窗口在屏幕中Y位置 int lastWinY = 0; //边框最大化前Rect QRect lastMoveRect; /// /// \brief borderMax 边框最大化 /// void borderMax(); /// /// \brief left 左尺寸改变操作 /// \param diffX 鼠标按下到当前X移动距离 /// void left(int diffX); /// /// \brief right 右尺寸改变操作 /// \param diffX 鼠标按下到当前X移动距离 /// void right(int diffX); /// /// \brief right 上尺寸改变操作 /// \param diffY 鼠标按下到当前Y移动距离 /// void top(int diffY); /// /// \brief right 下尺寸改变操作 /// \param diffY 鼠标按下到当前Y移动距离 /// void bottom(int diffY); }; #endif // QFRAMEDEMO_H
qframedemo.cpp:
#include "qframedemo.h" #include <QPainter> #include <QDebug> #include <QMouseEvent> #include <QApplication> #include <QDesktopWidget> QFrameDemo::QFrameDemo(QWidget *widget) : QFrame(NULL) { this->widget = widget; this->setAttribute(Qt::WA_TranslucentBackground, true); setWindowFlags(Qt::FramelessWindowHint); qDebug() << widget->x(); this->borderRect = widget->geometry(); move(this->borderRect.x(), this->borderRect.y()); } void QFrameDemo::paintEvent(QPaintEvent *) { QPainter pen(this); QPen p; p.setWidth(3); p.setColor(Qt::gray); pen.setPen(p); pen.drawRect(QRect(0, 0, this->borderRect.width(), this->borderRect.height())); this->setMinimumSize(this->borderRect.width(), this->borderRect.height()); } bool QFrameDemo::setCursorState(int mouseX, int mouseY) { state = NORMAL; //左上 if(mouseX < padding && mouseY < padding) { state = LEFT_TOP; widget->setCursor(Qt::SizeFDiagCursor); } //左下 if(mouseX < padding && mouseY > widget->height() - padding) { state = LEFT_BOTTOM; widget->setCursor(Qt::SizeBDiagCursor); } //右上 if(mouseX > this->widget->width() - padding && mouseY < padding) { state = RIGHT_TOP; widget->setCursor(Qt::SizeBDiagCursor); } //右下 if(mouseX > this->widget->width() - padding && mouseY > this->widget->height() - padding) { state = RIGHT_BOTTOM; widget->setCursor(Qt::SizeFDiagCursor); } //防止和其他单一方向冲突 if(state != NORMAL) { return true; } //左 if(mouseX < padding) { state = LEFT; widget->setCursor(Qt::SizeHorCursor); } //右 if(mouseX > widget->width() - padding) { state = RIGHT; widget->setCursor(Qt::SizeHorCursor); } //上 if(mouseY < padding) { state = TOP; widget->setCursor(Qt::SizeVerCursor); } //下 if(mouseY > widget->height() - padding) { state = BOTTOM; widget->setCursor(Qt::SizeVerCursor); } if(state == NORMAL) { widget->setCursor(Qt::ArrowCursor); return false; } return true; } void QFrameDemo::moveEvent(QMouseEvent *event) { if(isPress == false) { setCursorState(event->x(), event->y()); return ; } //鼠标从按下点到当前点距离 int diffX = event->x() - this->lastMouseX; int diffY = event->y() - this->lastMouseY; int tmpWidth, tmpHeigh; switch (this->state) { case LEFT_TOP: //左+上操作 if(diffX < 0) { tmpWidth = this->widget->width() + abs(diffX); } else { tmpWidth = this->widget->width() - diffX; } if(tmpWidth > this->widget->minimumWidth()) { this->borderRect.setWidth(tmpWidth); this->repaint(); } else { diffX = this->widget->width() - this->widget->minimumWidth(); } if(diffY > 0) { tmpHeigh = this->widget->height() - diffY; } else { tmpHeigh = this->widget->height() + abs(diffY); } if(tmpHeigh > this->widget->minimumHeight()) { this->borderRect.setHeight(tmpHeigh); this->repaint(); } else { diffY = this->widget->height() - this->widget->minimumHeight(); } this->move(lastWinX + diffX, lastWinY + diffY); break; case LEFT_BOTTOM: //左+下操作 if(diffX < 0) { tmpWidth = this->widget->width() + abs(diffX); } else { tmpWidth = this->widget->width() - diffX; } if(tmpWidth > this->widget->minimumWidth()) { this->borderRect.setWidth(tmpWidth); this->repaint(); } else { diffX = this->widget->width() - this->widget->minimumWidth(); } tmpHeigh = this->widget->height() + diffY; if(tmpHeigh > widget->minimumHeight()) { this->borderRect.setHeight(tmpHeigh); this->repaint(); } move(this->lastWinX + diffX, this->lastWinY); break; case RIGHT_TOP: //右+上操作 if(this->widget->width() + diffX > this->widget->minimumWidth()) { this->borderRect.setWidth(this->widget->width() + diffX); } if(diffY > 0) { tmpHeigh = this->widget->height() - diffY; } else { tmpHeigh = this->widget->height() + abs(diffY); } if(tmpHeigh > this->widget->minimumHeight()) { this->borderRect.setHeight(tmpHeigh); } else { diffY = this->widget->height() - this->widget->minimumHeight(); } this->move(this->x(), lastWinY + diffY); this->repaint(); break; case RIGHT_BOTTOM: //右+下操作 if(this->widget->width() + diffX > this->widget->minimumWidth()) { this->borderRect.setWidth(this->widget->width() + diffX); } if(this->widget->height() + diffX > this->widget->minimumHeight()) { this->borderRect.setHeight(this->widget->height() + diffY); } this->repaint(); break; case LEFT: left(diffX); break; case RIGHT: right(diffX); break; case TOP: top(diffY); break; case BOTTOM: bottom(diffY); break; case NORMAL: //移动窗口 QRect rect = QApplication::desktop()->geometry(); //当鼠标拖动边框到距离上屏幕1像素时,记录最大化前边框宽高;最大化边框,否则还原边框 if(lastWinY + event->y() < 1) { borderMax(); } else { //还原边框 if(windowState() == Qt::WindowMaximized && event->y() - lastMouseY > 1) { //当最大化下鼠标下拉时处理,还原窗口 this->borderRect = this->lastMoveRect; this->repaint(); setWindowState(Qt::WindowNoState); lastWinX = event->x() - (this->borderRect.width() / 2); lastWinY = event->y() - 20; } if(windowState() != Qt::WindowMaximized) { move(lastWinX + diffX, lastWinY + diffY); if(lastWinY + diffY < 1 && widget->windowState() == Qt::WindowMaximized) { //窗口最大化时鼠标下拉还原边窗口未松开左键,又上拉放大处理 borderMax(); } } if(windowState() == Qt::WindowMaximized && lastMouseY > 1 && this->widget->width() != rect.width() && this->widget->height() != rect.height()) { //当最大化边框拉下来又拉上去,又拉下来时处理 this->borderRect = this->lastMoveRect; setWindowState(Qt::WindowNoState); } } break; } } void QFrameDemo::press(QMouseEvent *event) { if(event->button() != Qt::LeftButton) { return ; } this->flushPos(); this->show(); isPress = true; this->lastMouseX = event->x(); this->lastMouseY = event->y(); if(windowState() != Qt::WindowMaximized) { this->lastWinX = this->x(); this->lastWinY = this->y(); } } void QFrameDemo::release(QMouseEvent *event) { if(event->button() != Qt::LeftButton) { return ; } isPress = false; this->hide(); widget->setGeometry(this->borderRect); widget->move(this->x(), this->y()); widget->setWindowState(windowState()); } void QFrameDemo::flushPos() { move(this->widget->x(), this->widget->y()); this->borderRect = widget->geometry(); } void QFrameDemo::borderMax() { QRect rect = QApplication::desktop()->geometry(); //此处判断防止重复给lastMoveRect赋值,导致还原时不正常 if(rect.width() == this->borderRect.width() && this->x() == 0 && this->y() == 0) { return ; } //最大化边框 this->lastMoveRect = this->borderRect; setWindowState(Qt::WindowMaximized); this->move(0, 0); // this->borderRect = rect; this->borderRect = this->rect(); this->repaint(); } void QFrameDemo::left(int diffX) { int width; if(diffX < 0) { width = this->widget->width() + abs(diffX); } else { width = this->widget->width() - diffX; } if(width > this->widget->minimumWidth()) { this->borderRect.setWidth(width); move(this->lastWinX + diffX, this->lastWinY); this->repaint(); } } void QFrameDemo::right(int diffX) { int width = this->widget->width() + diffX; if(width > widget->minimumWidth()) { this->borderRect.setWidth(this->widget->width() + diffX); } this->repaint(); } void QFrameDemo::top(int diffY) { int height; if(diffY > 0) { height = this->widget->height() - diffY; } else { height = this->widget->height() + abs(diffY); } if(height > widget->minimumHeight()) { this->borderRect.setHeight(height); this->move(this->x(), lastWinY + diffY); this->repaint(); } } void QFrameDemo::bottom(int diffY) { int height = this->widget->height() + diffY; if(height > widget->minimumHeight()) { this->borderRect.setHeight(height); this->repaint(); } }
使用QFrameDemo:
1. 重写窗口左键按下、释放、鼠标移动事件
void mousePressEvent(QMouseEvent * event); void mouseMoveEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent * event);
2. 声明QFrameDemo和构造函数创建QFrameDemo
QFrameDemo *demo = nullptr;//声明 Dialog::Dialog(QWidget *parent) : QDialog(parent) , ui(new Ui::Dialog) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint);//设置无边框 setMouseTracking(true);//设置鼠标追踪 demo = new QFrameDemo(this);//设置当前窗口为控制窗口 }
3. 调用moveEvent、press、release
void Dialog::mouseMoveEvent(QMouseEvent *e) { //鼠标移动调用 demo->moveEvent(e); } void Dialog::mousePressEvent(QMouseEvent * event){ //按下调用 demo->press(event); } void Dialog::mouseReleaseEvent(QMouseEvent * event){ //释放调用 demo->release(event); }
以Dialog窗口为例:
dialog.h
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QMouseEvent> QT_BEGIN_NAMESPACE namespace Ui { class Dialog; } QT_END_NAMESPACE class Dialog : public QDialog { Q_OBJECT public: Dialog(QWidget *parent = nullptr); ~Dialog(); void mousePressEvent(QMouseEvent * event); void mouseMoveEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent * event); private slots: void on_pushButton_clicked(); private: Ui::Dialog *ui; }; #endif // DIALOG_H
dialog.cpp
//封装的类,方便控制窗口
QFrameDemo *demo = nullptr; Dialog::Dialog(QWidget *parent) : QDialog(parent) , ui(new Ui::Dialog) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint);//设置无边框 setMouseTracking(true);//设置鼠标追踪 demo = new QFrameDemo(this);//设置当前窗口为控制窗口 } void Dialog::mouseMoveEvent(QMouseEvent *e) {
//鼠标移动调用 demo->moveEvent(e); } void Dialog::mousePressEvent(QMouseEvent * event){
//按下调用 demo->press(event); } void Dialog::mouseReleaseEvent(QMouseEvent * event){
//释放调用 demo->release(event); }
setMouseTra
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!