国庆没啥事,研究了一下 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 之自定义界面(窗体缩放-跨平台终极版)
学习分享,一起成长!以上为小编的经验分享,若存在不当之处,请批评指正!