个人感觉系统自带的边框美观上稍微欠缺一点,这也是好多软件去掉边框的原因吧。
去掉边框后,就能自由在任何位置添加一个自己的边框、标题栏之类的,甚至可以在上面添加一些工具菜单。
使用下面这个函数就能去掉边框:
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint);
//第一个参数是设置无边框。第二个参数是允许任务栏按钮右键菜单,第三个参数是允许最小化与还原。
使用第一个参数即可。
去掉边框后,发现鼠标也无法移动窗口,也无法自由调整大小。要说最小最大化、关闭的话,这个可以添加两个按钮来实现。
于是,我网上开始查找一些资料、自己也思考了一下,大概如下解决:
这个自然是重写鼠标点击、移动事件了。
步骤一:鼠标点击,记录鼠标点击时的位置。
步骤二:鼠标移动,根据鼠标当前的位置和起始位置,计算出鼠标的位移,然后设置窗口的新位置。
这个是比较麻烦的,网上找了好多资料,都没有完美的实现方法。
网上比较多的是下面两种做法:
一种是调用Windows API来实现,但是这样就失去了跨平台的意义。
一种是通过重写鼠标的region和move事件来实现,但是有些小BUG。
通过第二种方法和我的调试以及一些思考,提出以下做法:
条件一:首先,鼠标region窗体时,而且距离边框进入某个阈值PADDING时,此时被认为可以自动调整窗体大小。而且此效果优先于移动窗口的效果。
条件二:满足第一步的情况下,按下鼠标左键,并且移动鼠标,将改变窗体的大小。不过根据鼠标的位置会朝不同的方向改变。比如在窗体左边界附近,那么只会左侧的窗体扩展或者收缩。
在前面两个条件下,确实能满足自由调整大小,但是会出现一个问题。在主窗体中,某些子组件在鼠标进入时,主窗体会失去对鼠标的检测。可是在鼠标点击的时候,主窗体又会再次获得鼠标的检测。所以会出现,当鼠标进入主窗体,激活region效果,然后鼠标进入子组件后,鼠标位移了好长一段距离,主窗体的region效果仍然存在,此时如果鼠标左击,同时触发第二个条件,然后窗体一下子大小就变了。以上是我进过反复调试得到的结论。
然后考虑到出现此BUG的最主要缘故是,子组件获得鼠标移动的检测时,主窗体会丢失鼠标的检测。但是网上找了好多方法都没有解决这个问题的,网上有些说设置mouseTracking可以解决,但是有些组件可以解决,有些组件无效。
于是我想了一个办法:既然无法解决鼠标的事情,就考虑重置region那个效果。当子组件获得鼠标检测的时候,也就是mouseenter的时候,会发出一个mouseenter的信号,然后父组件接收这个信号的时候,触发losemouse事件,重置region效果。这样只需要对每个边界处的子组件,编写mouseenter事件就可以解决上面的BUG了。
具体代码:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
//PADDING用于设置改变窗口时鼠标侦测的边距
#define PADDING 4
enum Direction
{
UP,
DOWN,
LEFT,
RIGHT,
LEFTTOP,
LEFTBOTTOM,
RIGHTBOTTOM,
RIGHTTOP,
NONE
};
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
public slots:
void loseMouse();//当鼠标焦点被子组件获取时,需要还原鼠标形状和changeDir。
void setMaxSize();
private:
void region(const QPoint &cursorGlobalPoint);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
protected:
bool isMaxSize;
bool isLeftPressDown;//判断左键是否按下
QPoint dragPosition;//窗口移动拖动时需要记住的点
Direction changeDir;//窗口大小改变时,记录改变方向
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QMouseEvent>
#include <QApplication>
#include <QDesktopWidget>
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
resize(970, 700);
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint);
//第一个参数是设置无边框。第二个参数是允许任务栏按钮右键菜单,第三个参数是允许最小化与还原。
isLeftPressDown = false;
isMaxSize = false;
changeDir = NONE;
setMaximumWidth(QApplication::desktop()->width());
setMaximumHeight(QApplication::desktop()->height());
setMinimumHeight(570);
setMinimumWidth(985);
setMouseTracking(true);//追踪鼠标
//this->setStyleSheet("QDialog{background:url(:/bg_main.png)}");//设置样式背景色,可有可无
this->setFocusPolicy(Qt::ClickFocus);//主窗口设置鼠标点击焦点,新建歌单时有用
}
void MainWindow::setMaxSize()
{
if (this->isMaxSize)
{
this->isMaxSize = false;
this->showNormal();
}
else
{
this->isMaxSize = true;
this->showMaximized();
}
}
void MainWindow::region(const QPoint &cursorGlobalPoint)
{
if (isMaxSize)
return;
//获取窗体在屏幕上的位置区域,tl为topleft点,rb为rightbottom点
QRect rect = this->rect();
QPoint topleft = mapToGlobal(rect.topLeft());
QPoint rightbottom = mapToGlobal(rect.bottomRight());
int x = cursorGlobalPoint.x();
int y = cursorGlobalPoint.y();
if(topleft.x()+PADDING >= x &&
topleft.x() <= x &&
topleft.y()+PADDING >= y &&
topleft.y() <= y)
{
// 左上角
changeDir = LEFTTOP;
this->setCursor(QCursor(Qt::SizeFDiagCursor));//设置鼠标形状
}
else if(x >= rightbottom.x()-PADDING &&
x <= rightbottom.x() &&
y >= rightbottom.y()-PADDING &&
y <= rightbottom.y())
{
// 右下角
changeDir = RIGHTBOTTOM;
this->setCursor(QCursor(Qt::SizeFDiagCursor));
}
else if(x <= topleft.x()+PADDING &&
x >= topleft.x() &&
y >= rightbottom.y()-PADDING &&
y <= rightbottom.y())
{
//左下角
changeDir = LEFTBOTTOM;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if(x <= rightbottom.x() &&
x >= rightbottom.x()-PADDING &&
y >= topleft.y() &&
y <= topleft.y()+PADDING)
{
// 右上角
changeDir = RIGHTTOP;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if(x <= topleft.x()+PADDING &&
x >= topleft.x())
{
// 左边
changeDir = LEFT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if(x <= rightbottom.x() &&
x >= rightbottom.x()-PADDING)
{
// 右边
changeDir = RIGHT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if(y >= topleft.y() &&
y <= topleft.y()+PADDING)
{
// 上边
changeDir = UP;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else if(y <= rightbottom.y() &&
y >= rightbottom.y()-PADDING)
{
// 下边
changeDir = DOWN;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else
{
// 默认
changeDir = NONE;
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
void MainWindow::loseMouse()
{
changeDir = NONE;
this->setCursor(QCursor(Qt::ArrowCursor));
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
if (isMaxSize)
return;
if(event->button() == Qt::LeftButton)
{
isLeftPressDown = false;
if(changeDir != NONE)
{
this->releaseMouse();
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (isMaxSize)
return;
if (event->button() == Qt::LeftButton)
{
isLeftPressDown = true;
if(changeDir != NONE)
this->mouseGrabber();
else
dragPosition = event->globalPos() - this->frameGeometry().topLeft();
}
else
QWidget::mousePressEvent(event);
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if (isMaxSize)
return;
QPoint globalPoint = event->globalPos();
QRect rect = this->rect();
QPoint topleft = mapToGlobal(rect.topLeft());
QPoint bottomright = mapToGlobal(rect.bottomRight());
if(!isLeftPressDown)
{
this->region(globalPoint);
}
else if(changeDir != NONE)
{
QRect rMove(topleft, bottomright);
switch(changeDir)
{
case LEFT:
if(bottomright.x() - globalPoint.x() <= this->minimumWidth())
rMove.setX(topleft.x());
else
rMove.setX(globalPoint.x());
break;
case RIGHT:
rMove.setWidth(globalPoint.x() - topleft.x());
break;
case UP:
if(bottomright.y() - globalPoint.y() <= this->minimumHeight())
rMove.setY(topleft.y());
else
rMove.setY(globalPoint.y());
break;
case DOWN:
rMove.setHeight(globalPoint.y() - topleft.y());
break;
case LEFTTOP:
if(bottomright.x() - globalPoint.x() <= this->minimumWidth())
rMove.setX(topleft.x());
else
rMove.setX(globalPoint.x());
if(bottomright.y() - globalPoint.y() <= this->minimumHeight())
rMove.setY(topleft.y());
else
rMove.setY(globalPoint.y());
break;
case RIGHTTOP:
rMove.setWidth(globalPoint.x() - topleft.x());
rMove.setY(globalPoint.y());
break;
case LEFTBOTTOM:
rMove.setX(globalPoint.x());
rMove.setHeight(globalPoint.y() - topleft.y());
break;
case RIGHTBOTTOM:
rMove.setWidth(globalPoint.x() - topleft.x());
rMove.setHeight(globalPoint.y() - topleft.y());
break;
default:
break;
}
this->setGeometry(rMove);
}
else
{
move(event->globalPos() - dragPosition);
//event->accept();
}
QWidget::mouseMoveEvent(event);
}