目录

什么情况下需要自定义边框?

效果图

一、基本思路

二、参考程序一

2.1 源码

2.2 思路说明

2.3 缺点说明

三、参考程序2

3.1 源码

3.2 思路说明

3.3 优缺点说明

四、参考程序3

4.1源码

4.2 思路说明

4.3 优缺点说明

4.4 GitHub

五、结语


什么情况下需要自定义边框?

  由于QT对修改标题栏样式的支持有限,处于美化的考虑常常会使用使用无边框模式,并自己设计标题栏样式。

  使用 setWindowFlag(Qt::FramelessWindowHint);  关闭QT窗口边框后,也会导致窗口拉伸缩放功能失效。

  因此,需要使用自定义边框的方式,来实现窗口的拉升缩放。

效果图


QT series 设置线宽 qt设置边框宽度_QT series 设置线宽

自定义边框拉伸效果演示

一、基本思路

  对于自定义边框样式,网上的方案有很多,但是归根结底都是一个基本思路

  捕获鼠标位置→在指定位置显示指定的鼠标样式→点击后捕获当前的点击位置→鼠标移动,依据点击的位置,计算位移→将位移反馈给窗体→窗体依据位移进行缩放拉伸→鼠标释放,释放捕获。

二、参考程序一

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种程序的哪种方案,亦或者网上的其他方案,都不重要。相比于纠结哪种实现过程,实现的思路更为重要。编程时,多思考因为-所以才是最快乐的。

  什么?你还想要窗体可以拖动?那当然是封装一个标题栏啦!(待更新)

  如果你有什么不懂的地方,亦或者发现博主某个地方存在错误,欢迎留言交流。感谢你的反馈。

  如果你觉得这篇文章对你有帮助,请在文章的左下角点个赞。