目录
什么情况下需要自定义边框?
由于QT对修改标题栏样式的支持有限,处于美化的考虑常常会使用使用无边框模式,并自己设计标题栏样式。
使用 setWindowFlag(Qt::FramelessWindowHint); 关闭QT窗口边框后,也会导致窗口拉伸缩放功能失效。
因此,需要使用自定义边框的方式,来实现窗口的拉升缩放。
效果图
一、基本思路
对于自定义边框样式,网上的方案有很多,但是归根结底都是一个基本思路
捕获鼠标位置→在指定位置显示指定的鼠标样式→点击后捕获当前的点击位置→鼠标移动,依据点击的位置,计算位移→将位移反馈给窗体→窗体依据位移进行缩放拉伸→鼠标释放,释放捕获。
二、参考程序一
2.1 源码
MyBorder.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QObject>
#include <QLabel>
#include <QMouseEvent>
#include <qnamespace.h>
class MyBorder:public QLabel
{
Q_OBJECT
public:
MyBorder(QWidget *parent=nullptr);
void setScaleCursor(int nshape = 0);
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
QPoint m_mousePointOld;
bool m_bKeepDrag;
signals:
void moveEventSig(QPoint point);
void mouseReleasedSig();
};
#endif // MYLABEL_H
MyBorder.cpp
#include "MyBorder.h"
MyBorder::MyBorder(QWidget *parent):m_bKeepDrag(false)
{
this->setParent(parent);
}
void MyBorder::setScaleCursor(int nshape)
{
if(nshape == 1)//左右拉伸
{
setCursor(Qt::SizeHorCursor); //改变光标形状
}
else if(nshape == 2)//上下拉伸
{
setCursor(Qt::SizeVerCursor);
}
else if(nshape == 3)//右下拉伸
{
setCursor(Qt::SizeFDiagCursor);
}
else if(nshape == 4)//左下拉伸
{
setCursor(Qt::SizeBDiagCursor);
}
else //正常显示
{
setCursor(Qt::ArrowCursor);
}
}
void MyBorder::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
m_bKeepDrag = true; //拉伸标志
m_mousePointOld = ev->globalPos();
}
}
void MyBorder::mouseMoveEvent(QMouseEvent *ev)
{
if(m_bKeepDrag)
{
const QPoint position = ev->globalPos() - m_mousePointOld; //the position of mainfrmae + (current_mouse_position - last_mouse_position)
//move(position.x(), position.y());
emit moveEventSig(position);
m_mousePointOld = ev->globalPos();
}
}
void MyBorder::mouseReleaseEvent(QMouseEvent *ev)
{
Q_UNUSED(ev)
m_bKeepDrag = false;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <MyBorder/MyBorder.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void getLeftScaleEvent(QPoint movPoint);
void getRightScaleEvent(QPoint movPoint);
void getBottomScaleEvent(QPoint movPoint);
void getTopScaleEvent(QPoint movPoint);
void getRBScaleEvent(QPoint movPoint);
void getRTScaleEvent(QPoint movPoint);
void getLTScaleEvent(QPoint movPoint);
void getLBScaleEvent(QPoint movPoint);
private:
void DarwBorder();
void InitBorder();
uint16_t minWindowHeight; //最小窗口高度
uint16_t minWindowWidth; //最小窗口宽度
//边框控件
MyBorder *labelLft;
MyBorder *labelRit;
MyBorder *labelBot;
MyBorder *labelTop;
MyBorder *labelRB;
MyBorder *labelRT;
MyBorder *labelLB;
MyBorder *labelLT;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowFlag(Qt::FramelessWindowHint);
InitBorder();
}
MainWindow::~MainWindow()
{
delete ui;
}
//初始化左右边框
void MainWindow::InitBorder()
{
minWindowWidth = 1000; //最小窗口宽度
minWindowHeight = 650; //最小窗口高度
//上下左右的label,为了控制界面能够拖动拉伸
labelLft = new MyBorder(this);
labelLft->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLft->raise();
labelLft->setScaleCursor(1);
labelRit = new MyBorder(this);
labelRit->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRit->raise();
labelRit->setScaleCursor(1);//设置为左右拉升光标
labelBot = new MyBorder(this);
labelBot->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelBot->raise();
labelBot->setScaleCursor(2);//设置为上下拉升光标
labelTop = new MyBorder(this);
labelTop->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelTop->setScaleCursor(2);//设置为上下拉升光标
labelRB = new MyBorder(this);
labelRB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRB->setScaleCursor(3);//设置为右下拉升光标
labelRT = new MyBorder(this);
labelRT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRT->setScaleCursor(4);//设置为右上拉升光标
labelLB = new MyBorder(this);
labelLB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLB->setScaleCursor(4);//设置为左下拉升光标
labelLT = new MyBorder(this);
labelLT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLT->setScaleCursor(3);//设置为左上拉升光标
//绘制边框
DarwBorder();
//关联回调函数
connect(labelLft, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLeftScaleEvent(QPoint)));
connect(labelRit, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRightScaleEvent(QPoint)));
connect(labelBot, SIGNAL(moveEventSig(QPoint)), this, SLOT(getBottomScaleEvent(QPoint)));
connect(labelTop, SIGNAL(moveEventSig(QPoint)), this, SLOT(getTopScaleEvent(QPoint)));
connect(labelRB, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRBScaleEvent(QPoint)));
connect(labelRT, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRTScaleEvent(QPoint)));
connect(labelLB, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLBScaleEvent(QPoint)));
connect(labelLT, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLTScaleEvent(QPoint)));
}
//重绘边框
void MainWindow::DarwBorder()
{
labelLft->setGeometry(0,0,5,this->height());
labelRit->setGeometry(this->width()-5,0,5,this->height());
labelBot->setGeometry(0,this->height()-5,this->width(),5);
labelTop->setGeometry(0,0,this->width(),5);
labelRB->setGeometry(this->width()-6,this->height()-6,this->width(),this->height());
labelRT->setGeometry(this->width()-6,0,this->width(),6);
labelLB->setGeometry(0,this->height()-6,6,this->width());
labelLT->setGeometry(0,0,6,6);
}
void MainWindow::getLeftScaleEvent(QPoint movPoint)
{
if((pos().x()+movPoint.x())>(pos().x()+this->width()-minWindowWidth))
{
return;//保证拖动窗口左边界的时候,控件宽度至少有200
}
this->setGeometry(pos().x()+movPoint.x(),pos().y(),this->width()-movPoint.x(),this->height());
DarwBorder();
}
void MainWindow::getRightScaleEvent(QPoint movPoint)
{
if((pos().x()+this->width()+movPoint.x())<(pos().x()+minWindowWidth))
{
return;//保证拖动窗口右边界的时候,控件宽度至少有200
}
this->setGeometry(pos().x(),pos().y(),this->width()+movPoint.x(),this->height());
DarwBorder();
}
void MainWindow::getBottomScaleEvent(QPoint movPoint)
{
if((pos().y()+this->height()+movPoint.y())<(pos().y()+minWindowHeight))
{
return;//保证拖动窗口下边界的时候,控件高度至少有200
}
this->setGeometry(pos().x(),pos().y(),this->width(),this->height()+movPoint.y());
DarwBorder();
}
void MainWindow::getTopScaleEvent(QPoint movPoint)
{
if((pos().y()+movPoint.y())>(pos().y()+this->height()-minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度至少有200
}
this->setGeometry(pos().x(),pos().y()+movPoint.y(),this->width(),this->height()-movPoint.y());
DarwBorder();
}
void MainWindow::getRBScaleEvent(QPoint movPoint)
{
if((pos().y()+this->height()+movPoint.y())<(pos().y()+minWindowHeight)
|| (pos().x()+this->width()+movPoint.x())<(pos().x()+minWindowWidth))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
this->setGeometry(pos().x(),pos().y(),this->width()+movPoint.x(),this->height());
this->setGeometry(pos().x(),pos().y(),this->width(),this->height()+movPoint.y());
DarwBorder();
}
void MainWindow::getRTScaleEvent(QPoint movPoint)
{
if((pos().x()+this->width()+movPoint.x())<(pos().x()+minWindowWidth)
|| (pos().y()+movPoint.y())>(pos().y()+this->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
this->setGeometry(pos().x(),pos().y()+movPoint.y(),this->width(),this->height()-movPoint.y());
this->setGeometry(pos().x(),pos().y(),this->width()+movPoint.x(),this->height());
DarwBorder();
}
void MainWindow::getLTScaleEvent(QPoint movPoint)
{
if((pos().x()+movPoint.x())>(pos().x()+this->width()-minWindowWidth)
|| (pos().y()+movPoint.y())>(pos().y()+this->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
this->setGeometry(pos().x()+movPoint.x(),pos().y(),this->width()-movPoint.x(),this->height());
this->setGeometry(pos().x(),pos().y()+movPoint.y(),this->width(),this->height()-movPoint.y());
DarwBorder();
}
void MainWindow::getLBScaleEvent(QPoint movPoint)
{
if((pos().x()+movPoint.x())>(pos().x()+this->width()-minWindowWidth)
|| (pos().y()+this->height()+movPoint.y())<(pos().y()+minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
this->setGeometry(pos().x()+movPoint.x(),pos().y(),this->width()-movPoint.x(),this->height());
this->setGeometry(pos().x(),pos().y(),this->width(),this->height()+movPoint.y());
DarwBorder();
}
2.2 思路说明
通过重写QLabel中的鼠标点击事件,鼠标移动事件,鼠标释放事件三个事件,并将QLabel绘制在主窗口的特定位置。特定事件产生时,将相关参数通过信号的方式传递给主窗口,从而控制主窗口进行拉伸缩放。
2.3 缺点说明
使用这种方式,能够实现自定义缩放功能没错,但是也有明显的缺点,和直接重现主窗口中的三个鼠标事件的方式一样(网上有这种方式),每个多一个新窗口都需要在新窗口的代码中重写一次初始化函数,关联回调函数等操作,就算是复制粘贴,窗口一多也会显得十分的麻烦。
因此,我们需要加入一点点细节,来解决这个问题,下面请看参考程序2。
三、参考程序2
3.1 源码
MyBorder.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QObject>
#include <QLabel>
#include <QMouseEvent>
#include <qnamespace.h>
class MyBorder:public QLabel
{
Q_OBJECT
public:
MyBorder(QWidget *parent=nullptr);
void setScaleCursor(int nshape = 0);
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
QPoint m_mousePointOld;
bool m_bKeepDrag;
signals:
void moveEventSig(QPoint point);
void mouseReleasedSig();
};
#endif // MYLABEL_H
MyBorder.cpp
#include "MyBorder.h"
MyBorder::MyBorder(QWidget *parent):m_bKeepDrag(false)
{
this->setParent(parent);
}
void MyBorder::setScaleCursor(int nshape)
{
if(nshape == 1)//左右拉伸
{
setCursor(Qt::SizeHorCursor); //改变光标形状
}
else if(nshape == 2)//上下拉伸
{
setCursor(Qt::SizeVerCursor);
}
else if(nshape == 3)//右下拉伸
{
setCursor(Qt::SizeFDiagCursor);
}
else if(nshape == 4)//左下拉伸
{
setCursor(Qt::SizeBDiagCursor);
}
else //正常显示
{
setCursor(Qt::ArrowCursor);
}
}
void MyBorder::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
m_bKeepDrag = true;
m_mousePointOld = ev->globalPos();
}
}
void MyBorder::mouseMoveEvent(QMouseEvent *ev)
{
if(m_bKeepDrag)
{
const QPoint position = ev->globalPos() - m_mousePointOld; //the position of mainfrmae + (current_mouse_position - last_mouse_position)
//move(position.x(), position.y());
emit moveEventSig(position);
m_mousePointOld = ev->globalPos();
}
}
void MyBorder::mouseReleaseEvent(QMouseEvent *ev)
{
Q_UNUSED(ev)
m_bKeepDrag = false;
}
MyBorderContainer.h
#ifndef MYBORDERCONTAINER_H
#define MYBORDERCONTAINER_H
#include "MyBorder.h"
#include <QWidget>
#include <QObject>
#include <QLabel>
#include <QMouseEvent>
class MyBorderContainer : public QObject
{
Q_OBJECT
public:
MyBorderContainer(QWidget *parent,uint16_t minWindowHeight = 50, uint16_t minWindowWidth = 50, uint16_t borderSize = 5);
void setMinWindowSize(uint16_t minWindowWidth, uint16_t minWindowHeight); //设置窗口最小尺寸
void setBorderSize(uint16_t borderSize); //设置边框捕获区域尺寸
void DarwBorder();
protected:
void InitBorder();
private slots:
void getLeftScaleEvent(QPoint movPoint);
void getRightScaleEvent(QPoint movPoint);
void getBottomScaleEvent(QPoint movPoint);
void getTopScaleEvent(QPoint movPoint);
void getRBScaleEvent(QPoint movPoint);
void getRTScaleEvent(QPoint movPoint);
void getLTScaleEvent(QPoint movPoint);
void getLBScaleEvent(QPoint movPoint);
private:
uint16_t minWindowHeight; //最小窗口高度
uint16_t minWindowWidth; //最小窗口宽度
uint16_t borderSize;
QWidget *forms;
//边框控件
MyBorder *labelLft;
MyBorder *labelRit;
MyBorder *labelBot;
MyBorder *labelTop;
MyBorder *labelRB;
MyBorder *labelRT;
MyBorder *labelLB;
MyBorder *labelLT;
};
#endif // MYBORDERCONTAINER_H
MyBorderContainer.cpp
#include "MyBorderContainer.h"
MyBorderContainer::MyBorderContainer(QWidget *parent,uint16_t minWindowHeight,uint16_t minWindowWidth, uint16_t borderSize)
{
forms = parent;
this->minWindowHeight = minWindowHeight; //最小窗口高度
this->minWindowWidth = minWindowWidth; //最小窗口宽度
this->borderSize = borderSize;
this->setParent(parent);
InitBorder();
}
void MyBorderContainer::InitBorder()
{
//上下左右的label,为了控制界面能够拖动拉伸
labelLft = new MyBorder(forms);
labelLft->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLft->raise();
labelLft->setScaleCursor(1);
connect(labelLft, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLeftScaleEvent(QPoint)));
labelRit = new MyBorder(forms);
labelRit->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRit->raise();
labelRit->setScaleCursor(1);//设置为左右拉升光标
connect(labelRit, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRightScaleEvent(QPoint)));
labelBot = new MyBorder(forms);
labelBot->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelBot->raise();
labelBot->setScaleCursor(2);//设置为上下拉升光标
connect(labelBot, SIGNAL(moveEventSig(QPoint)), this, SLOT(getBottomScaleEvent(QPoint)));
labelTop = new MyBorder(forms);
labelTop->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelTop->raise();
labelTop->setScaleCursor(2);//设置为上下拉升光标
connect(labelTop, SIGNAL(moveEventSig(QPoint)), this, SLOT(getTopScaleEvent(QPoint)));
labelRB = new MyBorder(forms);
labelRB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRB->raise();
labelRB->setScaleCursor(3);//设置为右下拉升光标
connect(labelRB, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRBScaleEvent(QPoint)));
labelRT = new MyBorder(forms);
labelRT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRT->raise();
labelRT->setScaleCursor(4);//设置为右上拉升光标
connect(labelRT, SIGNAL(moveEventSig(QPoint)), this, SLOT(getRTScaleEvent(QPoint)));
labelLB = new MyBorder(forms);
labelLB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLB->raise();
labelLB->setScaleCursor(4);//设置为左下拉升光标
connect(labelLB, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLBScaleEvent(QPoint)));
labelLT = new MyBorder(forms);
labelLT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLT->raise();
labelLT->setScaleCursor(3);//设置为左上拉升光标
connect(labelLT, SIGNAL(moveEventSig(QPoint)), this, SLOT(getLTScaleEvent(QPoint)));
DarwBorder();
}
void MyBorderContainer::setMinWindowSize(uint16_t minWindowWidth, uint16_t minWindowHeight)
{
this->minWindowHeight = minWindowHeight; //最小窗口高度
this->minWindowWidth = minWindowWidth; //最小窗口宽度
}
void MyBorderContainer::setBorderSize(uint16_t borderSize)
{
this->borderSize = borderSize;
}
//重绘边框
void MyBorderContainer::DarwBorder()
{
labelLft->setGeometry(0,0,this->borderSize,forms->height());
labelRit->setGeometry(forms->width()-this->borderSize,0,this->borderSize,forms->height());
labelBot->setGeometry(0,forms->height()-this->borderSize,forms->width(),this->borderSize);
labelTop->setGeometry(0,0,forms->width(),this->borderSize);
labelRB->setGeometry(forms->width()-this->borderSize-1,forms->height()-this->borderSize-1,forms->width(),forms->height());
labelRT->setGeometry(forms->width()-this->borderSize-1,0,forms->width(),this->borderSize+1);
labelLB->setGeometry(0,forms->height()-this->borderSize-1,this->borderSize+1,forms->width());
labelLT->setGeometry(0,0,this->borderSize+1,this->borderSize+1);
}
void MyBorderContainer::getLeftScaleEvent(QPoint movPoint)
{
if((forms->pos().x()+movPoint.x())>(forms->pos().x()+forms->width()-minWindowWidth))
{
return;//保证拖动窗口左边界的时候,控件宽度至少有最小值
}
forms->setGeometry(forms->pos().x()+movPoint.x(),forms->pos().y(),forms->width()-movPoint.x(),forms->height());
DarwBorder();
}
void MyBorderContainer::getRightScaleEvent(QPoint movPoint)
{
if((forms->pos().x()+forms->width()+movPoint.x())<(forms->pos().x()+minWindowWidth))
{
return;//保证拖动窗口右边界的时候,控件宽度至少有最小值
}
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width()+movPoint.x(),forms->height());
DarwBorder();
}
void MyBorderContainer::getBottomScaleEvent(QPoint movPoint)
{
if((forms->pos().y()+forms->height()+movPoint.y())<(forms->pos().y()+minWindowHeight))
{
return;//保证拖动窗口下边界的时候,控件高度至少有最小值
}
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width(),forms->height()+movPoint.y());
DarwBorder();
}
void MyBorderContainer::getTopScaleEvent(QPoint movPoint)
{
if((forms->pos().y()+movPoint.y())>(forms->pos().y()+forms->height()-minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度至少有最小值
}
forms->setGeometry(forms->pos().x(),forms->pos().y()+movPoint.y(),forms->width(),forms->height()-movPoint.y());
DarwBorder();
}
void MyBorderContainer::getRBScaleEvent(QPoint movPoint)
{
if((forms->pos().y()+forms->height()+movPoint.y())<(forms->pos().y()+minWindowHeight)
|| (forms->pos().x()+forms->width()+movPoint.x())<(forms->pos().x()+minWindowWidth))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有最小值
}
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width()+movPoint.x(),forms->height());
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width(),forms->height()+movPoint.y());
DarwBorder();
}
void MyBorderContainer::getRTScaleEvent(QPoint movPoint)
{
if((forms->pos().x()+forms->width()+movPoint.x())<(forms->pos().x()+minWindowWidth)
|| (forms->pos().y()+movPoint.y())>(forms->pos().y()+forms->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有最小值
}
forms->setGeometry(forms->pos().x(),forms->pos().y()+movPoint.y(),forms->width(),forms->height()-movPoint.y());
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width()+movPoint.x(),forms->height());
DarwBorder();
}
void MyBorderContainer::getLTScaleEvent(QPoint movPoint)
{
if((forms->pos().x()+movPoint.x())>(forms->pos().x()+forms->width()-minWindowWidth)
|| (forms->pos().y()+movPoint.y())>(forms->pos().y()+forms->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有最小值
}
forms->setGeometry(forms->pos().x()+movPoint.x(),forms->pos().y(),forms->width()-movPoint.x(),forms->height());
forms->setGeometry(forms->pos().x(),forms->pos().y()+movPoint.y(),forms->width(),forms->height()-movPoint.y());
DarwBorder();
}
void MyBorderContainer::getLBScaleEvent(QPoint movPoint)
{
if((forms->pos().x()+movPoint.x())>(forms->pos().x()+forms->width()-minWindowWidth)
|| (forms->pos().y()+forms->height()+movPoint.y())<(forms->pos().y()+minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有最小值
}
forms->setGeometry(forms->pos().x()+movPoint.x(),forms->pos().y(),forms->width()-movPoint.x(),forms->height());
forms->setGeometry(forms->pos().x(),forms->pos().y(),forms->width(),forms->height()+movPoint.y());
DarwBorder();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <MyBorder/MyBorderContainer.h>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private:
MyBorderContainer *My;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowFlag(Qt::FramelessWindowHint);
My = new MyBorderContainer(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
3.2 思路说明
实现思路与参考程序1基本相同,不同点在于该程序对程序1进行了一层封装。建立一个边框管理类(MyBorderContainer),用于生成和管理边框。将特定的窗体指针传递给边框管理类进行托管即可。
3.3 优缺点说明
优点:相较于程序1,该程序只需要在窗体中创建一个边框管理类(MyBorderContainer),然后将自己的指针(this)传递给边框管理类进行托管即可。
一行代码解决问题的感觉确实很爽呢。
缺点:虽然对边框类进行了封装,但是由于边框类(MyBorder)依旧是一个独立的类,能够在其他类(除了MyBorderContainer以外)方法中创建。通常,这并不是我们想要的。
因此,我们可以再加入一点点小细节,来解决这个问题,下面请看参考程序3。
四、参考程序3
4.1源码
MyBorderContainer.h
#ifndef MYBORDERCONTAINER_H
#define MYBORDERCONTAINER_H
#include <QWidget>
#include <QObject>
#include <QLabel>
#include <QMouseEvent>
enum BorderType
{
NULL_BORDER = 0, // 无
L_BORDER, // 左
R_BORDER, // 右
T_BORDER, // 上
B_BORDER, // 下
LT_BORDER, // 左上
LB_BORDER, //左下
RT_BORDER, //右上
RB_BORDER, //右下
};
class MyBorderContainer : public QObject
{
Q_OBJECT
public:
MyBorderContainer(QWidget *parent,uint16_t minWindowHeight = 50, uint16_t minWindowWidth = 50, uint16_t borderSize = 5);
void setMinWindowSize(uint16_t minWindowWidth, uint16_t minWindowHeight); //设置窗口最小尺寸
void setBorderSize(uint16_t borderSize); //设置边框捕获区域尺寸
void DarwBorder(); //重新绘制边框(调整位置)
protected:
void InitBorder(); //初始化边框
private:
void getLeftScaleEvent(QPoint movPoint);
void getRightScaleEvent(QPoint movPoint);
void getBottomScaleEvent(QPoint movPoint);
void getTopScaleEvent(QPoint movPoint);
void getRBScaleEvent(QPoint movPoint);
void getRTScaleEvent(QPoint movPoint);
void getLTScaleEvent(QPoint movPoint);
void getLBScaleEvent(QPoint movPoint);
//内部边框类,防止外部创建
class MyBorder:public QLabel
{
public:
//设置边框属性
MyBorder(QWidget *parent, BorderType type, MyBorderContainer * outClass);
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
private:
MyBorderContainer *container; //保存外部类指针
BorderType MyType;
QPoint mousePointOld;
bool KeepDrag;
};
uint16_t borderSize; //边框捕获区大小
uint16_t minWindowHeight; //最小窗口高度
uint16_t minWindowWidth; //最小窗口宽度
QWidget *m_widget;
//边框控件
MyBorder *labelLft;
MyBorder *labelRit;
MyBorder *labelBot;
MyBorder *labelTop;
MyBorder *labelRB;
MyBorder *labelRT;
MyBorder *labelLB;
MyBorder *labelLT;
};
#endif // MYBORDERCONTAINER_H
MyBorder.cpp
#include "MyBorderContainer.h"
MyBorderContainer::MyBorder::MyBorder(QWidget *parent, BorderType type, MyBorderContainer * contex)
{
this->setParent(parent);
KeepDrag = false;
MyType = type;
container = contex;
if(MyType == L_BORDER || MyType == R_BORDER)
{
setCursor(Qt::SizeHorCursor);
}
else if(MyType == T_BORDER || MyType == B_BORDER)
{
setCursor(Qt::SizeVerCursor);
}
else if(MyType == LT_BORDER || MyType == RB_BORDER)
{
setCursor(Qt::SizeFDiagCursor);
}
else if(MyType == LB_BORDER || MyType == RT_BORDER)
{
setCursor(Qt::SizeBDiagCursor);
}
else
{
setCursor(Qt::ArrowCursor);
}
}
//鼠标点击事件
void MyBorderContainer::MyBorder::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
KeepDrag = true;
mousePointOld = ev->globalPos();
}
return QWidget::mousePressEvent(ev);
}
//鼠标移动事件
void MyBorderContainer::MyBorder::mouseMoveEvent(QMouseEvent *ev)
{
if(KeepDrag)
{
const QPoint position = ev->globalPos() - mousePointOld;
//调用外部类接口
switch (MyType) {
case L_BORDER: //左
container->getLeftScaleEvent(position);
break;
case R_BORDER: //右
container->getRightScaleEvent(position);
break;
case T_BORDER: //上
container->getTopScaleEvent(position);
break;
case B_BORDER: //上
container->getBottomScaleEvent(position);
break;
case RB_BORDER: //右下
container->getRBScaleEvent(position);
break;
case RT_BORDER: //右上
container->getRTScaleEvent(position);
break;
case LB_BORDER: //左下
container->getLBScaleEvent(position);
break;
case LT_BORDER: //左上
container->getLTScaleEvent(position);
break;
default:
break;
}
mousePointOld = ev->globalPos();
}
return QWidget::mouseMoveEvent(ev);
}
//鼠标释放事件
void MyBorderContainer::MyBorder::mouseReleaseEvent(QMouseEvent *ev)
{
Q_UNUSED(ev)
KeepDrag = false;
return QWidget::mouseReleaseEvent(ev);
}
MyBorderContainer.cpp
#include "MyBorderContainer.h"
MyBorderContainer::MyBorderContainer(QWidget *parent,uint16_t minWindowHeight,uint16_t minWindowWidth, uint16_t borderSize)
{
m_widget = parent;
this->minWindowHeight = minWindowHeight; //最小窗口高度
this->minWindowWidth = minWindowWidth; //最小窗口宽度
this->borderSize = borderSize;
this->setParent(parent);
InitBorder();
}
void MyBorderContainer::InitBorder()
{
//上下左右的label,为了控制界面能够拖动拉伸
labelLft = new MyBorder(m_widget, L_BORDER, this);
labelLft->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLft->raise();
labelRit = new MyBorder(m_widget, R_BORDER, this);
labelRit->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRit->raise();
labelBot = new MyBorder(m_widget, B_BORDER, this);
labelBot->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelBot->raise();
labelTop = new MyBorder(m_widget, T_BORDER, this);
labelTop->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelTop->raise();
labelRB = new MyBorder(m_widget, RB_BORDER, this);
labelRB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRB->raise();
labelRT = new MyBorder(m_widget, RT_BORDER, this);
labelRT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelRT->raise();
labelLB = new MyBorder(m_widget, LB_BORDER, this);
labelLB->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLB->raise();
labelLT = new MyBorder(m_widget, LT_BORDER, this);
labelLT->setStyleSheet("QLabel {background-color: transparent;}");//设置背景透明
labelLT->raise();
DarwBorder();
}
void MyBorderContainer::setMinWindowSize(uint16_t minWindowWidth, uint16_t minWindowHeight)
{
this->minWindowHeight = minWindowHeight; //最小窗口高度
this->minWindowWidth = minWindowWidth; //最小窗口宽度
}
void MyBorderContainer::setBorderSize(uint16_t borderSize)
{
this->borderSize = borderSize;
}
//重绘边框
void MyBorderContainer::DarwBorder()
{
labelLft->setGeometry(0,0,this->borderSize,m_widget->height());
labelRit->setGeometry(m_widget->width()-this->borderSize,0,this->borderSize,m_widget->height());
labelBot->setGeometry(0,m_widget->height()-this->borderSize,m_widget->width(),this->borderSize);
labelTop->setGeometry(0,0,m_widget->width(),this->borderSize);
labelRB->setGeometry(m_widget->width()-this->borderSize-1,m_widget->height()-this->borderSize-1,m_widget->width(),m_widget->height());
labelRT->setGeometry(m_widget->width()-this->borderSize-1,0,m_widget->width(),this->borderSize+1);
labelLB->setGeometry(0,m_widget->height()-this->borderSize-1,this->borderSize+1,m_widget->width());
labelLT->setGeometry(0,0,this->borderSize+1,this->borderSize+1);
}
void MyBorderContainer::getLeftScaleEvent(QPoint movPoint)
{
if((m_widget->pos().x()+movPoint.x())>(m_widget->pos().x()+m_widget->width()-minWindowWidth))
{
return;//保证拖动窗口左边界的时候,控件宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x()+movPoint.x(),m_widget->pos().y(),m_widget->width()-movPoint.x(),m_widget->height());
DarwBorder();
}
void MyBorderContainer::getRightScaleEvent(QPoint movPoint)
{
if((m_widget->pos().x()+m_widget->width()+movPoint.x())<(m_widget->pos().x()+minWindowWidth))
{
return;//保证拖动窗口右边界的时候,控件宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width()+movPoint.x(),m_widget->height());
DarwBorder();
}
void MyBorderContainer::getBottomScaleEvent(QPoint movPoint)
{
if((m_widget->pos().y()+m_widget->height()+movPoint.y())<(m_widget->pos().y()+minWindowHeight))
{
return;//保证拖动窗口下边界的时候,控件高度至少有200
}
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width(),m_widget->height()+movPoint.y());
DarwBorder();
}
void MyBorderContainer::getTopScaleEvent(QPoint movPoint)
{
if((m_widget->pos().y()+movPoint.y())>(m_widget->pos().y()+m_widget->height()-minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度至少有200
}
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y()+movPoint.y(),m_widget->width(),m_widget->height()-movPoint.y());
DarwBorder();
}
void MyBorderContainer::getRBScaleEvent(QPoint movPoint)
{
if((m_widget->pos().y()+m_widget->height()+movPoint.y())<(m_widget->pos().y()+minWindowHeight)
|| (m_widget->pos().x()+m_widget->width()+movPoint.x())<(m_widget->pos().x()+minWindowWidth))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width()+movPoint.x(),m_widget->height());
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width(),m_widget->height()+movPoint.y());
DarwBorder();
}
void MyBorderContainer::getRTScaleEvent(QPoint movPoint)
{
if((m_widget->pos().x()+m_widget->width()+movPoint.x())<(m_widget->pos().x()+minWindowWidth)
|| (m_widget->pos().y()+movPoint.y())>(m_widget->pos().y()+m_widget->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y()+movPoint.y(),m_widget->width(),m_widget->height()-movPoint.y());
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width()+movPoint.x(),m_widget->height());
DarwBorder();
}
void MyBorderContainer::getLTScaleEvent(QPoint movPoint)
{
if((m_widget->pos().x()+movPoint.x())>(m_widget->pos().x()+m_widget->width()-minWindowWidth)
|| (m_widget->pos().y()+movPoint.y())>(m_widget->pos().y()+m_widget->height()-minWindowHeight) )
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x()+movPoint.x(),m_widget->pos().y(),m_widget->width()-movPoint.x(),m_widget->height());
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y()+movPoint.y(),m_widget->width(),m_widget->height()-movPoint.y());
DarwBorder();
}
void MyBorderContainer::getLBScaleEvent(QPoint movPoint)
{
if((m_widget->pos().x()+movPoint.x())>(m_widget->pos().x()+m_widget->width()-minWindowWidth)
|| (m_widget->pos().y()+m_widget->height()+movPoint.y())<(m_widget->pos().y()+minWindowHeight))
{
return;//保证拖动窗口上边界的时候,控件高度和宽度至少有200
}
m_widget->setGeometry(m_widget->pos().x()+movPoint.x(),m_widget->pos().y(),m_widget->width()-movPoint.x(),m_widget->height());
m_widget->setGeometry(m_widget->pos().x(),m_widget->pos().y(),m_widget->width(),m_widget->height()+movPoint.y());
DarwBorder();
}
4.2 思路说明
该程序将边框类(MyBorder)设置为边框管理类(MyBorderContainer)的内部类,这样就可以让外部无法创建MyBorder对象。
4.3 优缺点说明
参考程序3进一步加深了程序的封装程度,将MyBorder.h和MyBorderContainer.h以及MyBorderContainer.cpp三个文件打包后,就可以当做一个模块来使用了,非常方便,当然封装有利有弊,应该根据实际需要进行选择。
4.4 GitHub
目前以及将参考程序3打包成模块,并编写了简单的Demo上传至GitHub上
链接:BorderDemo
将其中的BorderDemo.pro文件导入Qt Creator并选择自己的编译器即可使用。
五、结语
不论你选择以上3种程序的哪种方案,亦或者网上的其他方案,都不重要。相比于纠结哪种实现过程,实现的思路更为重要。编程时,多思考因为-所以才是最快乐的。
什么?你还想要窗体可以拖动?那当然是封装一个标题栏啦!(待更新)
如果你有什么不懂的地方,亦或者发现博主某个地方存在错误,欢迎留言交流。感谢你的反馈。
如果你觉得这篇文章对你有帮助,请在文章的左下角点个赞。