QT窗口缩放,自定义边框,无边框缩放拉伸

目录

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

效果图

一、基本思路

二、参考程序一

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窗口边框后,也会导致窗口拉伸缩放功能失效。

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

效果图

自定义边框拉伸效果演示

一、基本思路

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

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

二、参考程序一

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

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

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

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值