赞
踩
国庆没啥事,研究了一下 Qt 实现自定义窗口,参考了两位博主的文章,自己做了点修改,修复了一些 Bug(有可能是我没按大佬的思路来产生的),目前还存在的 Bug 是最大化窗口被移动了以后,需要点击两次窗口还原按钮才能还原窗口,不想再耗费时间再纠结这个问题了,后面有需要的话再来改就完事,下面是主要源码:
zoomMove.h
enum { EDGENULL = 0, TOPLEFT, TOPRIGHT, BOTTOMRIGHT, BOTTOMLEFT, TOP, RIGHT, BOTTOM, LEFT }; class ZoomMove : public QWidget { Q_OBJECT public: explicit ZoomMove(QWidget *parent = nullptr); ~ZoomMove(); private: bool key_down, //0:松开, 1:按下 zoom, //0:无操作, 1:拉扯 move; //0:无操作, 1:移动 int is_on_edge, //0:不沾边, 1:上边, 2:右上方 , 3:右边 , 4:右下方 , 5:下边 , 6:左下方 , 7:左边 , 8:左上方 left, top, right, bottom, min_width, min_height; QPoint last_point, //当前窗口的左上方顶点 current_point, //当前鼠标相对于屏幕的位置,不能将 current_point 与 point 看作同一坐标点,后者没有前者稳定 point, //当前鼠标在屏幕中的位置 temp_point; //用于存放窗口的四个顶点 QWidget *widget; void updateCursor(); //更新鼠标图标 void mouseIsOnEdge(QPoint point, QRect rect); //判断鼠标是否在边停靠 void resizeWidget(QPoint p); //根据拉伸重置窗口大小 void widgetEventHandler(QEvent *e); //窗口事件处理 void mouseHoverEventHandler(QHoverEvent *e); //鼠标停靠窗口 void mouseMoveEventHandler(QMouseEvent *e); //鼠标移动 void mousePressEventHandler(QMouseEvent *e); //鼠标被按下 void mouseReleaseEventHandler(QMouseEvent *e); //鼠标被松开 protected: virtual bool eventFilter(QObject *obj, QEvent *e); };
zoomMove.cpp
ZoomMove::ZoomMove(QWidget *parent): QWidget(parent) { key_down = //默认鼠标为松开状态 zoom = //默认无拉扯操作 move = 0; //默认无移动操作 is_on_edge = 0; //默认鼠标没有在边停靠 parent -> installEventFilter(this); //开启事件过滤 } ZoomMove::~ZoomMove() { widget -> removeEventFilter(this); //关闭事件过滤 } void ZoomMove::updateCursor() { switch(is_on_edge) { case TOPLEFT: //左上方 case BOTTOMRIGHT: //右下方 widget -> setCursor(Qt::SizeFDiagCursor); //左上-右下 break; case TOPRIGHT: //右上方 case BOTTOMLEFT: //左下方 widget -> setCursor(Qt::SizeBDiagCursor); //右上-左下 break; case TOP: //上边 case BOTTOM: //下边 widget -> setCursor(Qt::SizeVerCursor); //上-下 break; case RIGHT: //右边 case LEFT: //左边 widget -> setCursor(Qt::SizeHorCursor); //左-右 break; case EDGENULL: default: widget -> setCursor(Qt::ArrowCursor); //箭头 break; } } void ZoomMove::mouseIsOnEdge(QPoint point, QRect rect) { if((point.x() - rect.x() < 5) && (point.y() - rect.y() < 5)) { is_on_edge = TOPLEFT; //左上方 } else if((rect.x() + rect.width() - point.x() < 5) && (point.y() - rect.y() < 5)) { is_on_edge = TOPRIGHT; //右上方 } else if((rect.x() + rect.width() - point.x() < 5) && (rect.y() + rect.height() - point.y() < 5)) { is_on_edge = BOTTOMRIGHT; //右下方 } else if((point.x() - rect.x() < 5) && (rect.y() + rect.height() - point.y() < 5)) { is_on_edge = BOTTOMLEFT; //左下方 } else if(point.y() - rect.y() < 5) { is_on_edge = TOP; //上边 } else if(rect.x() + rect.width() - point.x() < 5) { is_on_edge = RIGHT; //右边 } else if(rect.y() + rect.height() - point.y() < 5) { is_on_edge = BOTTOM; //下边 } else if(point.x() - rect.x() < 5) { is_on_edge = LEFT; //左边 } else { is_on_edge = EDGENULL; //不沾边 } zoom = is_on_edge == EDGENULL ? 0 : 1; } void ZoomMove::resizeWidget(QPoint p) { min_width = widget -> minimumWidth(); min_height = widget -> minimumHeight(); QRect frame = widget -> frameGeometry(); //获取窗口的几何框架 switch(is_on_edge) { //根据边框的位置改变窗口的形状 case TOPLEFT: //左上方 temp_point = frame.topLeft(); if(frame.bottomRight().x() - p.x() > min_width) { temp_point.setX(p.x()); } if(frame.bottomRight().y() - p.y() > min_height) { temp_point.setY(p.y()); } if(frame.bottomRight().x() - p.x() <= min_width && frame.bottomRight().y() - p.y() <= min_height) { temp_point.setX(frame.bottomRight().x() - min_width); temp_point.setY(frame.bottomRight().y() - min_height); } frame.setTopLeft(temp_point); break; case TOPRIGHT: //右上方 temp_point = frame.topRight(); if(p.x() - frame.bottomLeft().x() > 0) { temp_point.setX(p.x()); } if(frame.bottomLeft().y() - p.y() > min_height) { temp_point.setY(p.y()); } if(p.x() - frame.bottomLeft().x() <= 0 && frame.bottomLeft().y() - p.y() <= min_height) { temp_point.setX(p.x()); temp_point.setY(frame.bottomLeft().y() - min_height); } frame.setTopRight(temp_point); break; case BOTTOMRIGHT: //右下方 temp_point = frame.bottomRight(); if(p.x() - frame.topLeft().x() > 0) { temp_point.setX(p.x()); } if(p.y() - frame.topLeft().y() > 0) { temp_point.setY(p.y()); } if(p.x() - frame.topLeft().x() <= 0 && p.y() - frame.topLeft().y() <= 0) { temp_point.setX(p.x()); temp_point.setY(p.y()); } frame.setBottomRight(temp_point); break; case BOTTOMLEFT: //左下方 temp_point = frame.bottomLeft(); if(frame.topRight().x() - p.x() > min_width) { temp_point.setX(p.x()); } if(p.y() - frame.topRight().y() > 0) { temp_point.setY(p.y()); } if(frame.topRight().x() - p.x() <= min_width && p.y() - frame.topRight().y() <= 0) { temp_point.setX(frame.topRight().x() - min_width); temp_point.setY(p.y()); } frame.setBottomLeft(temp_point); break; case TOP: //上边 temp_point = frame.topRight(); if(frame.bottomLeft().y() - p.y() > min_height) { temp_point.setY(p.y()); } frame.setTopRight(temp_point); break; case RIGHT: //右边 temp_point = frame.bottomRight(); if(p.x() - frame.topLeft().x() > 0) { temp_point.setX(p.x()); } frame.setBottomRight(temp_point); break; case BOTTOM: //下边 temp_point = frame.bottomLeft(); if(p.y() - frame.topRight().y() > 0) { temp_point.setY(p.y()); } frame.setBottomLeft(temp_point); break; case LEFT: //左边 temp_point = frame.topLeft(); if(frame.bottomRight().x() - p.x() > min_width) { temp_point.setX(p.x()); } frame.setTopLeft(temp_point); break; default: break; } widget -> setGeometry(frame); //给窗口设置新的几何框架 } void ZoomMove::widgetEventHandler(QEvent *e) { switch(e -> type()) { case QEvent::HoverMove: mouseHoverEventHandler(static_cast<QHoverEvent *>(e)); break; case QEvent::MouseMove: mouseMoveEventHandler(static_cast<QMouseEvent *>(e)); break; case QEvent::MouseButtonPress: mousePressEventHandler(static_cast<QMouseEvent *>(e)); break; case QEvent::MouseButtonRelease: mouseReleaseEventHandler(static_cast<QMouseEvent *>(e)); break; default: break; } } void ZoomMove::mouseHoverEventHandler(QHoverEvent *e) { if(!key_down){ //在窗口被拉扯或移动的过程中,停止对鼠标的悬浮监听 point = widget -> mapToGlobal(e -> pos()); mouseIsOnEdge(point, widget -> frameGeometry()); updateCursor(); } } void ZoomMove::mouseMoveEventHandler(QMouseEvent *e) { Q_UNUSED(e); if(key_down) { current_point = e -> globalPos(); //current_point - last_point 即窗口的左上角顶点 if(move && last_point.y() < 65) { widget -> move(current_point - last_point); } if(zoom) { resizeWidget(current_point); } } } void ZoomMove::mousePressEventHandler(QMouseEvent *e) { if(e -> button() == Qt::LeftButton) { key_down = 1; move = (!zoom && !move) & 1; last_point = e -> pos(); } } void ZoomMove::mouseReleaseEventHandler(QMouseEvent *e) { if(e -> button() == Qt::LeftButton) { key_down = //按键松开 move = 0; //更正移动状态 } } bool ZoomMove::eventFilter(QObject *obj, QEvent *e) { switch(e -> type()) { case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::HoverMove: widget = static_cast<QWidget *>(obj); widgetEventHandler(e); return true; default: return QObject::eventFilter(obj, e); } }
在 QMainWindow 或 QWidget 中初始化该类即可实现自定义窗口的拉伸与移动功能。
new ZoomMove(this);
参考博文:
前行中的小猪:Qt 之 自定义窗口标题栏 之窗口拉伸
一去丶二三里:Qt 之自定义界面(窗体缩放-跨平台终极版)
学习分享,一起成长!以上为小编的经验分享,若存在不当之处,请批评指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。