赞
踩
目录
本篇为作者第一次学做无边框窗口的历程
在构造函数内实现:
- //最小宽高
- this->setMinimumWidth(500);
- this->setMinimumHeight(300);
- //消除窗口边框
- setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
- //设置背景色
- this->setStyleSheet("background-color:#303030");
- //创建两个按钮
- btn1=new QPushButton(this);
- btn2=new QPushButton(this);
- btn1->setText("确认");
- btn2->setText("取消");
- btn1->setStyleSheet(R"(QPushButton {
- background-color: rgb(64, 64, 64);
- color:rgb(200,200,200);
- border: 1px solid #707070;
- border-radius: 5px;
- padding: 5px;
- })");
- btn2->setStyleSheet(R"(QPushButton {
- background-color: rgb(64, 64, 64);
- color:rgb(200,200,200);
- border: 1px solid #707070;
- border-radius: 5px;
- padding: 5px;
- })");
- QHBoxLayout* hor=new QHBoxLayout(this);
- hor->setSpacing(0);
- hor->setContentsMargins(10,10,10,10);
- hor->addWidget(btn1);
- hor->addWidget(btn2);
- //用于判断鼠标左键是否按下
- isleftpressed=false;
- //消除窗口边框
- setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
在这里先将基本的窗口呈现出来。
- void mousePressEvent(QMouseEvent* event);
- void mouseMoveEvent(QMouseEvent* event);
- void mouseReleaseEvent(QMouseEvent* event);
- enum Location {
- TOP,
- BOTTOM,
- LEFT,
- RIGHT,
- TOP_LEFT,
- TOP_RIGHT,
- BOTTOM_LEFT,
- BOTTOM_RIGHT,
- CENTER
- };
在一个窗口里,(0,0)是窗口的最左上角,往右或者是往下坐标都会变大。
在这里实现鼠标在窗口的八个方向的变化。
并放入鼠标移动事件,用于判断鼠标位置(location).
- #define padding 10
- QRect rect=this->rect();
- //将坐标转化为相对于整个屏幕的坐标
- QPoint topleft=mapToGlobal(rect.topLeft());
- QPoint bottomright=mapToGlobal(rect.bottomRight());
- int x=globalpos.x();
- int y=globalpos.y();
- //鼠标位于左上角
- if(x>topleft.x()&&x<topleft.x()+padding&&y>topleft.y()&&y<topleft.y()+padding)
- {
- location=TOP_LEFT;
- //这里鼠标光标变化
- this->setCursor(QCursor(Qt::SizeFDiagCursor));
- }
- //鼠标位于左下角
- else if(x>topleft.x()&&x<topleft.x()+padding&&y<bottomright.y()&&y>bottomright.y()-padding)
- {
- location=BOTTOM_LEFT;
- this->setCursor(QCursor(Qt::SizeBDiagCursor));
- }
- //鼠标位于右上角
- else if(x<bottomright.x()&&x>bottomright.x()-padding&&y>topleft.y()&&y<topleft.y()+padding)
- {
- location=TOP_RIGHT;
- this->setCursor(QCursor(Qt::SizeBDiagCursor));
- }
- //鼠标位于右下角
- else if(x<bottomright.x()&&x>bottomright.x()-padding&&y>bottomright.y()-padding&&y<bottomright.y())
- {
- location=BOTTOM_RIGHT;
- this->setCursor(Qt::SizeFDiagCursor);
- }
- //鼠标位于上面
- else if(y>topleft.y()&&y<topleft.y()+padding)
- {
- location=TOP;
- this->setCursor(Qt::SizeVerCursor);
-
- }
- //鼠标位于左边
- else if(x>topleft.x()&&x<topleft.x()+padding)
- {
- location=LEFT;
- this->setCursor(Qt::SizeHorCursor);
- }
- //鼠标位于下面
- else if(y>bottomright.y()-padding&&y<bottomright.y())
- {
- location=BOTTOM;
- this->setCursor(Qt::SizeVerCursor);
- }
- //鼠标位于右边
- else if(x<bottomright.x()&&x>bottomright.x()-padding)
- {
- location=RIGHT;
- this->setCursor(Qt::SizeHorCursor);
- }
- //鼠标位于中间
- else
- {
- location=CENTER;
- this->setCursor(QCursor(Qt::ArrowCursor));
- }
将其封装成函数,加入鼠标移动事件。
窗口边框消除后,右上角的叉叉也随之消失,于是我们加入一个右键关闭窗口的功能。
先前已经在头文件中加入了三个鼠标事件,现在来实现其中的按下事件
- void Widget::mousePressEvent(QMouseEvent* event)
- {
- switch (event->button())
- {
- //右键关闭窗口
- case Qt::RightButton:
- this->close();
- break;
- default:
- break;
- }
- }
在这里,需要记录鼠标的实时位置,并将窗口实时移动。
所以我们需要实时触发鼠标移动事件,并启用鼠标追踪。
this->setMouseTracking(true);
接下来实现修正鼠标按下和移动事件
- void Widget::mousePressEvent(QMouseEvent* event)
- {
- switch (event->button())
- {
- //右键关闭窗口
- case Qt::RightButton:
- this->close();
- break;
- //记录鼠标按下时位置与窗口左上角的距离
- case Qt::LeftButton:
- //用于判断左键是否按下
- isleftpressed=true;
- if(location==CENTER)
- mousepos=event->globalPos()-this->frameGeometry().topLeft();
- default:
- break;
- }
- }
窗口要移动到的新位置即是原窗口位置加上鼠标移动的位置。
鼠标移动时,实时触发。
- void Widget::mouseMoveEvent(QMouseEvent *event)
- {
- //这里是之前鼠标光标变化的函数
- if(!isleftpressed)
- {
- this->setcursorshape(globalpos);
- return;
- }
- //中间位置拖动窗口
- if(location==CENTER&&isleftpressed)
- {
- move(event->globalPos()-mousepos);
- event->accept();
- return;
- }
-
-
-
- }
在这里实现鼠标在边缘八个方向按下拉动时,窗口的变形。
即鼠标左键按下,触发鼠标移动事件时触发。
- void Widget::mouseMoveEvent(QMouseEvent *event)
- {
- //记录鼠标当前位置
- QPoint globalpos=event->globalPos();
- QRect rect=this->rect();
- QPoint topleft=mapToGlobal(rect.topLeft());
- QPoint bottomright=mapToGlobal(rect.bottomRight());
- //创建一个矩形,并拉伸,最后设置其为窗口
- QRect rmove(topleft,bottomright);
- switch (location)
- {
- case TOP:
- //这里的if防止最小后窗口整体向下移动
- if(bottomright.y()-globalpos.y()>this->minimumHeight())
- rmove.setY(globalpos.y());
- break;
- case BOTTOM:
- rmove.setHeight(globalpos.y()-topleft.y());
- break;
- case LEFT:
- if(bottomright.x()-globalpos.x()>this->minimumWidth())
- rmove.setX(globalpos.x());
- break;
- case RIGHT:
- rmove.setWidth(globalpos.x()-topleft.x());
- break;
- case TOP_LEFT:
- if(bottomright.y()-globalpos.y()>this->minimumHeight()&&bottomright.x()-globalpos.x()>this->width())
- {
- rmove.setY(globalpos.y());
- rmove.setX(globalpos.x());
- }
- break;
- case TOP_RIGHT:
- if(bottomright.y()-globalpos.y()>this->minimumHeight())
- {
- rmove.setY(globalpos.y());
- rmove.setWidth(globalpos.x()-topleft.x());
- }
- break;
- case BOTTOM_LEFT:
- if(bottomright.x()-globalpos.x()>this->width())
- {
- rmove.setHeight(globalpos.y()-topleft.y());
- rmove.setX(globalpos.x());
- }
- break;
- case BOTTOM_RIGHT:
- rmove.setHeight(globalpos.y()-topleft.y());
- rmove.setWidth(globalpos.x()-topleft.x());
- break;
- case CENTER:
- break;
- }
- //重新设置窗口几何形状
- this->setGeometry(rmove);
- return;
-
- }
需要注意的是在拖动顶部时,只需更新窗口的 Y 坐标,以实现向下拖动的效果。在拖动底部时,更新窗口的高度,以实现向上或向下调整大小的效果。这两种情况之所以有不同的处理方式,是因为拖动顶部只需要改变 Y 坐标,而拖动底部则需要改变高度。同样的逻辑也适用于左、右、左上、右上、左下、右下等不同的边界位置,因为每个位置的操作影响的窗口属性是不同的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。