zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    如何度过每天的最初十分钟
    微软正在拿命做一场豪赌
    .htaccess用法与设置超详细讲解+大全
    互联网+情趣用品:羞答答的玫瑰静悄悄地开
    男人雄辩 女人聊天
    苹果手表会一直美下去
    移动应用大行其道:你的企业准备好了吗?
    微商的下一步会怎么走?
    阿里京东腾讯58的O2O格局,创业者的夹缝生存之道
    苹果首席设计师艾维:Apple Watch不是奢侈品
  • 原文地址:https://www.cnblogs.com/GengMingYan/p/15313299.html
Copyright © 2011-2022 走看看