Qt 去掉边框 调整窗口宽高最大化最小化 仿 Windows操作窗口操作

去掉边框后想实现控制窗口的基本操作,但网上大多都是实时移动窗口,(比如移动窗口时,左键按下,窗口跟随鼠标实时移动; 不像windows 在移动时先有一个边框移动,当左键松开时实际窗口移动到边框位置)

用边框方式控制窗口尺寸时可以防止窗口频繁重绘控件(resizeEvent、paintEvent)。

封装了一个类QFrameDemo方便控制窗口使用,在末尾有使用示例:

qframedemo.h:

#ifndef QFRAMEDEMO_H
#define QFRAMEDEMO_H

#include <QFrame>
#define padding 10
enum State{
    LEFT,
    RIGHT,
    TOP,
    BOTTOM,
    LEFT_TOP,
    LEFT_BOTTOM,
    RIGHT_TOP,
    RIGHT_BOTTOM,
    NORMAL
};
class QFrameDemo : public QFrame
{
public:

    QFrameDemo(QWidget *widget);

    void paintEvent(QPaintEvent *);

    bool setCursorState(int mouseX, int mouseY);

    void moveEvent(QMouseEvent *event);

    void press(QMouseEvent *event);

    void release(QMouseEvent *event);

    void flushPos();

private:
    //画边框时QRect
    QRect borderRect;
    //当前鼠标状态
    State state;
    //让那个widget支持调整尺寸
    QWidget *widget;
    //是否左键被按下
    bool isPress = false;
    //左键按下是鼠标X位置,窗口坐上角为0,0
    int lastMouseX = 0;
    //左键按下是鼠标Y位置,窗口坐上角为0,0
    int lastMouseY =  0;
    //窗口在屏幕中X位置
    int lastWinX = 0;
    //窗口在屏幕中Y位置
    int lastWinY = 0;

    //边框最大化前Rect
    QRect lastMoveRect;

    ///
    /// \brief borderMax 边框最大化
    ///
    void borderMax();

    ///
    /// \brief left 左尺寸改变操作
    /// \param diffX 鼠标按下到当前X移动距离
    ///
    void left(int diffX);
    ///
    /// \brief right 右尺寸改变操作
    /// \param diffX 鼠标按下到当前X移动距离
    ///
    void right(int diffX);
    ///
    /// \brief right 上尺寸改变操作
    /// \param diffY 鼠标按下到当前Y移动距离
    ///
    void top(int diffY);
    ///
    /// \brief right 下尺寸改变操作
    /// \param diffY 鼠标按下到当前Y移动距离
    ///
    void bottom(int diffY);

};

#endif // QFRAMEDEMO_H

qframedemo.cpp:

#include "qframedemo.h"
#include <QPainter>
#include <QDebug>
#include <QMouseEvent>
#include <QApplication>
#include <QDesktopWidget>


QFrameDemo::QFrameDemo(QWidget *widget) : QFrame(NULL)
{
    this->widget = widget;
    this->setAttribute(Qt::WA_TranslucentBackground, true);
    setWindowFlags(Qt::FramelessWindowHint);
    qDebug() << widget->x();
    this->borderRect = widget->geometry();
    move(this->borderRect.x(), this->borderRect.y());
}

void QFrameDemo::paintEvent(QPaintEvent *)
{
    QPainter pen(this);
    QPen p;
    p.setWidth(3);
    p.setColor(Qt::gray);
    pen.setPen(p);
    pen.drawRect(QRect(0, 0, this->borderRect.width(), this->borderRect.height()));
    this->setMinimumSize(this->borderRect.width(), this->borderRect.height());
}


bool QFrameDemo::setCursorState(int mouseX, int mouseY)
{
    state = NORMAL;
    //左上
    if(mouseX < padding && mouseY < padding) {
        state = LEFT_TOP;
        widget->setCursor(Qt::SizeFDiagCursor);
    }
    //左下
    if(mouseX < padding && mouseY > widget->height() - padding) {
        state = LEFT_BOTTOM;
        widget->setCursor(Qt::SizeBDiagCursor);
    }
    //右上
    if(mouseX > this->widget->width() - padding && mouseY < padding) {
        state = RIGHT_TOP;
        widget->setCursor(Qt::SizeBDiagCursor);
    }
    //右下
    if(mouseX > this->widget->width() - padding && mouseY > this->widget->height() - padding) {
        state = RIGHT_BOTTOM;
        widget->setCursor(Qt::SizeFDiagCursor);
    }
    //防止和其他单一方向冲突
    if(state != NORMAL) {
        return true;
    }

    //
    if(mouseX < padding) {
        state = LEFT;
        widget->setCursor(Qt::SizeHorCursor);
    }
    //
    if(mouseX > widget->width() - padding) {
        state = RIGHT;
        widget->setCursor(Qt::SizeHorCursor);
    }
    //
    if(mouseY < padding) {
        state = TOP;
        widget->setCursor(Qt::SizeVerCursor);
    }
    //
    if(mouseY > widget->height() - padding) {
        state = BOTTOM;
        widget->setCursor(Qt::SizeVerCursor);
    }
    if(state == NORMAL) {
        widget->setCursor(Qt::ArrowCursor);
        return false;
    }
    return true;
}

void QFrameDemo::moveEvent(QMouseEvent *event)
{
    if(isPress == false) {
        setCursorState(event->x(), event->y());
        return ;
    }
    //鼠标从按下点到当前点距离
    int diffX = event->x() - this->lastMouseX;
    int diffY = event->y() - this->lastMouseY;
    int tmpWidth, tmpHeigh;
    switch (this->state) {
    case LEFT_TOP:
        //左+上操作
        if(diffX < 0) {
            tmpWidth = this->widget->width() + abs(diffX);
        } else {
            tmpWidth = this->widget->width() - diffX;
        }
        if(tmpWidth > this->widget->minimumWidth()) {
            this->borderRect.setWidth(tmpWidth);
            this->repaint();
        } else {
            diffX = this->widget->width() - this->widget->minimumWidth();
        }
        if(diffY > 0) {
            tmpHeigh = this->widget->height() - diffY;
        } else {
            tmpHeigh = this->widget->height() + abs(diffY);
        }
        if(tmpHeigh > this->widget->minimumHeight()) {
            this->borderRect.setHeight(tmpHeigh);
            this->repaint();
        } else {
            diffY = this->widget->height() - this->widget->minimumHeight();
        }
        this->move(lastWinX + diffX, lastWinY + diffY);
        break;
    case LEFT_BOTTOM:
        //左+下操作
        if(diffX < 0) {
            tmpWidth = this->widget->width() + abs(diffX);
        } else {
            tmpWidth = this->widget->width() - diffX;
        }
        if(tmpWidth > this->widget->minimumWidth()) {
            this->borderRect.setWidth(tmpWidth);
            this->repaint();
        } else {
            diffX = this->widget->width() - this->widget->minimumWidth();
        }
        tmpHeigh = this->widget->height() + diffY;
        if(tmpHeigh > widget->minimumHeight()) {
            this->borderRect.setHeight(tmpHeigh);
            this->repaint();
        }
        move(this->lastWinX + diffX, this->lastWinY);
        break;
    case RIGHT_TOP:
        //右+上操作
        if(this->widget->width() + diffX > this->widget->minimumWidth()) {
            this->borderRect.setWidth(this->widget->width() + diffX);
        }

        if(diffY > 0) {
            tmpHeigh = this->widget->height() - diffY;
        } else {
            tmpHeigh = this->widget->height() + abs(diffY);
        }
        if(tmpHeigh > this->widget->minimumHeight()) {
           this->borderRect.setHeight(tmpHeigh);
        } else {
            diffY = this->widget->height() - this->widget->minimumHeight();
        }
        this->move(this->x(), lastWinY + diffY);
        this->repaint();
        break;
    case RIGHT_BOTTOM:
        //右+下操作
        if(this->widget->width() + diffX > this->widget->minimumWidth()) {
            this->borderRect.setWidth(this->widget->width() + diffX);
        }
        if(this->widget->height() + diffX > this->widget->minimumHeight()) {
            this->borderRect.setHeight(this->widget->height() + diffY);
        }
        this->repaint();
        break;
    case LEFT:
        left(diffX);
        break;
    case RIGHT:
        right(diffX);
        break;
    case TOP:
        top(diffY);
        break;
    case BOTTOM:
        bottom(diffY);
        break;
    case NORMAL:
        //移动窗口
        QRect rect = QApplication::desktop()->geometry();
        //当鼠标拖动边框到距离上屏幕1像素时,记录最大化前边框宽高;最大化边框,否则还原边框
        if(lastWinY + event->y() < 1) {
            borderMax();
        } else {
            //还原边框
            if(windowState() == Qt::WindowMaximized && event->y() - lastMouseY > 1) {
                //当最大化下鼠标下拉时处理,还原窗口
                this->borderRect = this->lastMoveRect;
                this->repaint();
                setWindowState(Qt::WindowNoState);
                lastWinX = event->x() - (this->borderRect.width() / 2);
                lastWinY = event->y() - 20;
            }
            if(windowState() != Qt::WindowMaximized) {
                move(lastWinX + diffX, lastWinY + diffY);
                if(lastWinY + diffY < 1 && widget->windowState() == Qt::WindowMaximized) {
                    //窗口最大化时鼠标下拉还原边窗口未松开左键,又上拉放大处理
                    borderMax();
                }
            }
            if(windowState() == Qt::WindowMaximized && lastMouseY > 1 && this->widget->width() != rect.width() && this->widget->height() != rect.height()) {
                //当最大化边框拉下来又拉上去,又拉下来时处理
                this->borderRect = this->lastMoveRect;
                setWindowState(Qt::WindowNoState);
            }

        }
        break;
    }
}

void QFrameDemo::press(QMouseEvent *event)
{
    if(event->button() != Qt::LeftButton) {
        return ;
    }
    this->flushPos();
    this->show();
    isPress = true;
    this->lastMouseX = event->x();
    this->lastMouseY = event->y();
    if(windowState() != Qt::WindowMaximized) {
        this->lastWinX = this->x();
        this->lastWinY = this->y();
    }

}

void QFrameDemo::release(QMouseEvent *event)
{
    if(event->button() != Qt::LeftButton) {
        return ;
    }
    isPress = false;
    this->hide();
    widget->setGeometry(this->borderRect);
    widget->move(this->x(), this->y());
    widget->setWindowState(windowState());

}

void QFrameDemo::flushPos()
{
    move(this->widget->x(), this->widget->y());
    this->borderRect = widget->geometry();

}

void QFrameDemo::borderMax()
{
    QRect rect = QApplication::desktop()->geometry();
    //此处判断防止重复给lastMoveRect赋值,导致还原时不正常
    if(rect.width() == this->borderRect.width() && this->x() == 0 && this->y() == 0) {
        return ;
    }
    //最大化边框
    this->lastMoveRect = this->borderRect;
    setWindowState(Qt::WindowMaximized);
    this->move(0, 0);
//    this->borderRect = rect;
    this->borderRect = this->rect();
    this->repaint();
}

void QFrameDemo::left(int diffX)
{
    int width;
    if(diffX < 0) {
        width = this->widget->width() + abs(diffX);
    } else {
        width = this->widget->width() - diffX;
    }
    if(width > this->widget->minimumWidth()) {
        this->borderRect.setWidth(width);
        move(this->lastWinX + diffX, this->lastWinY);
        this->repaint();
    }
}

void QFrameDemo::right(int diffX)
{
    int width = this->widget->width() + diffX;
    if(width > widget->minimumWidth()) {
        this->borderRect.setWidth(this->widget->width() + diffX);
    }
    this->repaint();
}

void QFrameDemo::top(int diffY)
{
    int height;
    if(diffY > 0) {
        height = this->widget->height() - diffY;
    } else {
        height = this->widget->height() + abs(diffY);
    }
    if(height > widget->minimumHeight()) {
        this->borderRect.setHeight(height);
        this->move(this->x(), lastWinY + diffY);
        this->repaint();
    }
}

void QFrameDemo::bottom(int diffY)
{
    int height = this->widget->height() + diffY;
    if(height > widget->minimumHeight()) {
        this->borderRect.setHeight(height);
        this->repaint();
    }

}

使用QFrameDemo:

1. 重写窗口左键按下、释放、鼠标移动事件

    void mousePressEvent(QMouseEvent * event);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent * event);

2. 声明QFrameDemo和构造函数创建QFrameDemo

QFrameDemo *demo = nullptr;//声明
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    setWindowFlags(Qt::FramelessWindowHint);//设置无边框
    setMouseTracking(true);//设置鼠标追踪
    demo = new QFrameDemo(this);//设置当前窗口为控制窗口
}

3. 调用moveEvent、press、release

void Dialog::mouseMoveEvent(QMouseEvent *e)
{
  //鼠标移动调用
    demo->moveEvent(e);
}

void Dialog::mousePressEvent(QMouseEvent * event){
   //按下调用
    demo->press(event);
}

void Dialog::mouseReleaseEvent(QMouseEvent * event){
  //释放调用
    demo->release(event);
}

以Dialog窗口为例:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QMouseEvent>

QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();
    void mousePressEvent(QMouseEvent * event);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent * event);

private slots:


    void on_pushButton_clicked();

private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H

dialog.cpp

//封装的类,方便控制窗口
QFrameDemo *demo =
nullptr; Dialog::Dialog(QWidget *parent) : QDialog(parent) , ui(new Ui::Dialog) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint);//设置无边框 setMouseTracking(true);//设置鼠标追踪 demo = new QFrameDemo(this);//设置当前窗口为控制窗口 } void Dialog::mouseMoveEvent(QMouseEvent *e) {
  //鼠标移动调用 demo
->moveEvent(e); } void Dialog::mousePressEvent(QMouseEvent * event){
   //按下调用 demo
->press(event); } void Dialog::mouseReleaseEvent(QMouseEvent * event){
  //释放调用 demo
->release(event); }


setMouseTra
posted @ 2021-09-20 00:30  耿明岩  阅读(971)  评论(0编辑  收藏  举报
希望能帮助到你,顺利解决问题! ...G(^_−)☆