解决Qt设置无边框后无法通过鼠标拖动修改窗口大小问题

本文档介绍了如何在Qt应用程序中实现一个抽象主窗口,它允许用户通过鼠标操作改变窗口大小和位置。核心功能包括鼠标按下、移动和释放事件的处理,以及跟随鼠标移动的设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

头文件

#ifndef ABSTRACTMAINWINDOW_H
#define ABSTRACTMAINWINDOW_H

#include <QMainWindow>
#include <QPainter>
#include <QPaintEvent>
#include <QStyleOption>
#include <QMouseEvent>
#include <QPoint>
#include <QResizeEvent>

class AbstractMainWindow : public QMainWindow
{
    Q_OBJECT

    enum CursorPosition
    {
        None,
        TopLeft,
        Top,
        TopRight,
        Right,
        BottomRight,
        Bottom,
        BottomLeft,
        Left
    };

protected:
    QPoint m_startPos;
    bool m_isPressed = false;
    bool m_followMouseMove = false;
    Qt::CursorShape m_cursorShape = Qt::ArrowCursor;
    CursorPosition m_cursorPosition = None;
    bool m_cursorShapeChangable = true;
    int m_deltaLength = 10;

protected:
    AbstractMainWindow(QWidget* parent = nullptr);
    virtual bool construct();

    bool event(QEvent *event);
    void paintEvent(QPaintEvent* e);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

    void setCursorShape(Qt::CursorShape shape);

public:
    void setFollowMouseMove(bool value);
    void setCursorShapeChangable(bool value);
};

#endif // ABSTRACTMAINWINDOW_H

源文件

#include "AbstractMainWindow.h"
#include <QDebug>

AbstractMainWindow::AbstractMainWindow(QWidget* parent):QMainWindow(parent)
{
    //设置鼠标追踪
    setMouseTracking(true);
}

bool AbstractMainWindow::construct()
{
    return true;
}

bool AbstractMainWindow::event(QEvent *event)
{
    if(event->type() == QEvent::HoverMove)
    {
        /*          处理无边框后拖拽改变窗口大小问题          */
        //左上
        auto topLeftGPos = this->pos();
        //右上
        auto topRightGPos = QPoint(this->geometry().right(),y());
        //右下
        auto bottomRightGPos = QPoint(this->geometry().right(),this->geometry().bottom());
        //左下
        auto bottomLeftGPos = QPoint(x(),this->geometry().bottom());

        auto event_pos = cursor().pos();

        //在右边界
        if((topRightGPos.x() - m_deltaLength <= event_pos.x()) && (event_pos.x() <= topRightGPos.x() + m_deltaLength))
        {
            if(m_cursorShape == Qt::ArrowCursor)
            {
                if((topRightGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= topRightGPos.y() + m_deltaLength))
                {
                    m_cursorPosition = TopRight;
                    setCursorShape(Qt::SizeBDiagCursor);
                }
                else if((bottomRightGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= bottomRightGPos.y() + m_deltaLength))
                {
                    m_cursorPosition = BottomRight;
                    setCursorShape(Qt::SizeFDiagCursor);
                }
                else
                {
                    m_cursorPosition = Right;
                    setCursorShape(Qt::SizeHorCursor);
                }
            }
        }
        //在左边界
        else if((topLeftGPos.x() - m_deltaLength <= event_pos.x()) && (event_pos.x() <= topLeftGPos.x() + m_deltaLength))
        {
            if(m_cursorShape == Qt::ArrowCursor)
            {
                if((topLeftGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= topLeftGPos.y() + m_deltaLength))
                {
                    m_cursorPosition = TopLeft;
                    setCursorShape(Qt::SizeFDiagCursor);
                }
                else if((bottomLeftGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= bottomLeftGPos.y() + m_deltaLength))
                {
                    m_cursorPosition = BottomLeft;
                    setCursorShape(Qt::SizeBDiagCursor);
                }
                else
                {
                    m_cursorPosition = Left;
                    setCursorShape(Qt::SizeHorCursor);
                }
            }
        }
        //在上边界
        else if((topLeftGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= topLeftGPos.y() + m_deltaLength))
        {
            if(m_cursorShape == Qt::ArrowCursor)
            {
                m_cursorPosition = Top;
                setCursorShape(Qt::SizeVerCursor);
            }
        }
        //在下边界
        else if((bottomLeftGPos.y() - m_deltaLength <= event_pos.y()) && (event_pos.y() <= bottomLeftGPos.y() + m_deltaLength))
        {
            if(m_cursorShape == Qt::ArrowCursor)
            {
                m_cursorPosition = Bottom;
                setCursorShape(Qt::SizeVerCursor);
            }
        }
        else
        {
            m_cursorPosition = None;
            setCursorShape(Qt::ArrowCursor);
        }
    }

    return QMainWindow::event(event);
}

void AbstractMainWindow::paintEvent(QPaintEvent* e)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);

    (void)e;
}

void AbstractMainWindow::mousePressEvent(QMouseEvent *event)
{
    QMainWindow::mousePressEvent(event);

    if(m_followMouseMove)
    {
        if(event->button() == Qt::LeftButton)
        {
            m_isPressed = true;
            m_startPos = event->globalPos();
        }
    }

    m_cursorShape = cursor().shape();
}

void AbstractMainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(m_followMouseMove)
        m_isPressed = false;

    QMainWindow::mouseReleaseEvent(event);
}

void AbstractMainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(m_followMouseMove)
    {
        if(m_isPressed)
        {
            if(m_cursorShape == Qt::ArrowCursor)
            {
                auto offset = event->globalPos() - m_startPos;
                m_startPos = event->globalPos();
                move(x() + offset.x(),y() + offset.y());
            }
            else
            {
                auto offset = event->globalPos() - m_startPos;
                m_startPos = event->globalPos();

                switch(m_cursorPosition)
                {
                case TopLeft:
                {
                    move(x() + offset.x(),y() + offset.y());
                    resize(width() - offset.x(),height() - offset.y());
                    break;
                }
                case Top:
                {
                    move(x(),y() + offset.y());
                    resize(width(),height() - offset.y());
                    break;
                }
                case TopRight:
                {
                    resize(width() + offset.x(),height() - offset.y());
                    break;
                }
                case Right:
                {
                    resize(width() + offset.x(),height());
                    break;
                }
                case BottomRight:
                {
                    resize(width() + offset.x(),height() + offset.y());
                    break;
                }
                case Bottom:
                {
                    resize(width(),height() + offset.y());
                    break;
                }
                case BottomLeft:
                {
                    move(x() + offset.x(),y());
                    resize(width() - offset.x(),height() + offset.y());
                    break;
                }
                case Left:
                {
                    move(x() + offset.x(),y());
                    resize(width() - offset.x(),height());
                    break;
                }
                default:
                    break;
                }
            }
        }
    }

    QMainWindow::mouseMoveEvent(event);
}

void AbstractMainWindow::setFollowMouseMove(bool value)
{
    m_followMouseMove = value;
}

void AbstractMainWindow::setCursorShapeChangable(bool value)
{
    m_cursorShapeChangable = value;
}

void AbstractMainWindow::setCursorShape(Qt::CursorShape shape)
{
    if(m_cursorShapeChangable)
    {
        setCursor(shape);
    }
}


默认是不开启通过鼠标来移动窗口的,调用setFollowMouseMove(true)即可

QWidget同理,改个类名就行

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值