Qt - 实现自定义窗口可自由拉伸(方法2)

文件结构目录:

 

guimainwindow.h

#ifndef GUIMAINWINDOW_H
#define GUIMAINWINDOW_H

#include <QDialog>

QT_BEGIN_NAMESPACE
namespace Ui { class GUIMainWindow; }
QT_END_NAMESPACE

class GUIMainWindow : public QDialog
{
    Q_OBJECT

public:
    GUIMainWindow(QDialog *parent = nullptr);
    ~GUIMainWindow();
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    bool resizeWindow(QPoint pos);
    void checkMouseState(const QPoint &mPos);
    bool event(QEvent *e);

private:
    Ui::GUIMainWindow *ui;


    bool            left, right, top, bottom;//是否在窗口的左、右、上、下区域
    bool            m_bResizing;//是否缩放窗口
    bool            isLeftPressed;//左键是否按下
};
#endif // GUIMAINWINDOW_H

 

guimainwindow.cpp

#include "guimainwindow.h"
#include "ui_guimainwindow.h"
#include <QMouseEvent>
#include <QDebug>

GUIMainWindow::GUIMainWindow(QDialog *parent)
    : QDialog(parent)
    , ui(new Ui::GUIMainWindow)
{
    ui->setupUi(this);

    m_bResizing = false;
    isLeftPressed=false;
    left = false;
    right= false;
    top= false;
    bottom= false;
    qDebug()<<"GUIMainWindow> m_bResizing = "<<m_bResizing;
    this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);//窗口去标题栏,并且会去掉窗口拖拽移动功能和窗口自由拉伸功能
    this->setMouseTracking(true);//设置鼠标追踪
    this->setAttribute(Qt::WA_Hover, true);//开启鼠标悬停和点击功能
    this->setMinimumSize(800,600);
    //1.加载事件过滤器
    //this->installEventFilter(this);
}

GUIMainWindow::~GUIMainWindow()
{
    delete ui;
}

//new rain add
bool GUIMainWindow::resizeWindow(QPoint pos)
{
    qDebug()<<"resizeWindowz> m_bResizing = "<<m_bResizing;
    if ( m_bResizing )
    {
        QPoint point = mapToGlobal(pos);
        int x = point.x();
        int y = point.y();

        QRect g = geometry();

        if (left )//左边区域按下左键
        {
            if (g.right()-x>minimumSize().width())
            {
                g.setLeft( x );//g.left() + dx
            }
            else
            {
                g.setLeft(g.right()-minimumSize().width());
            }
        }
        if ( right )//右边区域按下左键
        {
            g.setRight( x );//g.right() + dx
        }
        if( top )//上边区域按下左键
        {
            g.setTop( y );
            if (g.bottom()-y>minimumSize().height())
            {
                g.setTop( y );//g.left() + dx
            }
            else
            {
                g.setTop(g.bottom()-minimumSize().height());
            }
        }
        if (bottom )//下边区域按下左键
        {
            g.setBottom( y);//g.bottom() + dy
        }

        setGeometry( g );
    }
    return m_bResizing;
}

void GUIMainWindow::checkMouseState(const QPoint &mPos)
{
    int x = mPos.x();
    int y = mPos.y();

//    QWidget * w = QApplication::widgetAt(mapToGlobal(mPos));//在全局屏幕位置点返回小部件,如果没有Qt小部件,则返回nullptr。这个函数可能很慢。
//    if(w!=this && w!=NULL)
//    {

//        left = false;
//        right = false;
//        bottom = false;
//        top = false;
//        m_bResizing=false;
//        qDebug()<<"checkMouseState> m_bResizing = "<<m_bResizing;
//        qDebug()<<"w!=this && w!=NULL";
//        setCursor( Qt::ArrowCursor );
//    }
//    else
//    {
//        qDebug()<<"w = NULL";
//    }

    QRect r = rect();
    left = qAbs( x - r.left() ) <= 3;    //计算窗口左边区域
    right = qAbs( x - r.right() ) <= 3;  //计算窗口右边区域
    bottom = qAbs( y - r.bottom() ) <= 3;//计算窗口下边区域
    //bool noTop = qAbs( y - r.top() ) > m_titleBar->height();
    top = qAbs( y - r.top() ) <= 2;      //计算窗口上边区域

    //left = left && noTop;
    //right = right && noTop;
    bool hor = left | right;

    if (hor && bottom )
    {
        if ( left )//鼠标在窗口左下角区域
        {
            setCursor( Qt::SizeBDiagCursor );
            qDebug()<<"左下角";
        }
        else//鼠标在窗口右下角区域
        {
            setCursor( Qt::SizeFDiagCursor );
            qDebug()<<"右下角";
        }
    }
    else if(hor && top)
    {
        if(left)//鼠标在窗口左上角区域
        {
            setCursor( Qt::SizeFDiagCursor );
            qDebug()<<"左上角";
        }
        else//鼠标在窗口右上角区域
        {
            setCursor( Qt::SizeBDiagCursor );
            qDebug()<<"右上角";
        }
    }
    else if (left)//鼠标在窗口左边区域
    {
        setCursor( Qt::SizeHorCursor );
    }
    else if(right)//鼠标在窗口右边区域
    {
        setCursor( Qt::SizeHorCursor );
    }
    else if (top)//鼠标在窗口上边区域
    {
        setCursor( Qt::SizeVerCursor );//grabMouse
    }
    else if (bottom)//鼠标在窗口下边区域
    {
        setCursor( Qt::SizeVerCursor );//grabMouse
    }
    else//鼠标不在以上区域
    {
        setCursor(Qt::ArrowCursor);
    }
}

void GUIMainWindow::mousePressEvent( QMouseEvent* e )
{
    if ( e->button() == Qt::LeftButton )
    {
        isLeftPressed = true;

        if(left || right || bottom || top)//如果鼠标在窗口左、右、上、下区域,则需要改变窗口
        {
            m_bResizing = true;
            qDebug()<<"鼠标在窗口左、右、上、下区域按下 ";
        }
    }
    //checkMouseState(e->pos());
    QDialog::mousePressEvent( e );
}

void GUIMainWindow::mouseReleaseEvent( QMouseEvent* e )
{
    if ( e->button() == Qt::LeftButton )
    {
        isLeftPressed = false;
        m_bResizing = false;
    }

    left = false;
    right= false;
    bottom= false;
    top= false;

    qDebug()<<"mouseReleaseEvent> m_bResizing = "<<m_bResizing;

    //releaseMouse();
    QDialog::mouseReleaseEvent( e );
}

bool GUIMainWindow::event(QEvent *e)
{
    if (e->type() == QEvent::HoverMove)//Qt的Widget默认是不会响应Hover类型的事件,如需要捕捉Hover类型事件,则需要对Widget执行:setAttribute(Qt::WA_Hover, true);
    {
        QHoverEvent* hoverEvent = static_cast<QHoverEvent*>(e);
        //QPoint mousePos = hoverEvent->pos();
        //m_ctrl->HoverEvent(this, mousePos);

        qDebug()<<"QEvent::HoverMove";

        if(!isLeftPressed)
        {
            checkMouseState(hoverEvent->pos());
            //resizeWindow(hoverEvent->pos());
            //qDebug()<<"鼠标左键没有按下";
        }
        else
        {
            resizeWindow(hoverEvent->pos());
            qDebug()<<"鼠标左键按下22";
        }

    }
    if(e->type() == QEvent::MouseButtonPress)
    {
        qDebug()<<"鼠标左键按下";
    }

    return QDialog::event(e);
}

 

main.cpp

#include "guimainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    GUIMainWindow widget;
    widget.show();

    return a.exec();
}

 

知识补充:

MouseMove

Qt中的mouseMove事件,默认情况下是需要按住鼠标左键移动时,才会相应Qt::mouseMoveEvent;

如果希望在鼠标不按住的情况下捕捉该事件:

1.对于单个Widget,需要对该Widget执行:

setMouseTracking(true);

2.对于父子窗口,父窗口若想捕捉子窗口上方的mouseMoveEvent,则父子窗口都需要执行:

setMouseTracking(true);

并且子窗口(控件)并未对该事件进行处理,即没有accept或ignore该事件,若子窗口(控件)重写了虚函数: void mouseMoveEvent(QMouseEvent *event) ;则父窗口是捕捉不到子窗口(控件)的mouseMoveEvent

3.举例,QMainWindow若想捕捉客户区域的mouseMove事件,则QMainWindow和其中的centralWidget子部件都需要执行 setMouseTracking(true);

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->centralWidget()->setMouseTracking(true);
    this->setMouseTracking(true);
}

若该MainWindow中有一个QPushButton和一个QLabel;鼠标在button和label上移动时,MainWindow都不能收到mouseMove事件,除非对button和label都执行setMouseTracking(true);

HoverMove

Qt的Widget默认是不会响应Hover类型的事件,如需要捕捉Hover类型事件,则需要对Widget执行:setAttribute(Qt::WA_Hover, true);

Qt的Hover事件包括:

1.QEvent::HoverEnter: 当鼠标进入widget的边界时,触发HoverEnter事件。这通常用于改变widget的视觉表现,例如突出显示对象以指示它是可操作的。

2.QEvent::HoverLeave: 当鼠标离开widget的边界时,触发HoverLeave事件。这通常用于恢复widget的原始视觉表现。

3.QEvent::HoverMove: 当鼠标在widget边界内移动时,触发HoverMove事件。这可能涉及到更具动态性的视觉反馈,例如改变光标形状,或将特定区域突出显示以响应鼠标位置。

对比

HoverMove相比于mouseMove,自带穿透的效果,继续以上QMainWindow的例子:

  • mouseMove事件是不会穿透button和label的,若MainWindow想要捕捉到在子控件上的mouseMove事件,除非子控件调用setMouseTracking(true);
  • hoverMove是会穿透子控件,给MainWindow(父控件)设置了setMouseTracking(true);后;即使鼠标在button或label上移动,父控件(窗口)依然能收到HoverMove事件
posted @ 2024-02-27 17:53  [BORUTO]  阅读(300)  评论(0编辑  收藏  举报