Qt无边框窗体移动和缩放

使用setWindowFlags(Qt::FramelessWindowHint);设置后的窗体是不可以移动、拉伸的,所以为了让无边框窗体移动就需要自己重写一些事件实现。
效果如下
这里写图片描述
图1 拖拽窗体
(注:当窗体左上角、左边、上边拖拽时会有抖动,有些电脑却没有这种情况。。具体为啥我也不知道( ⊙o⊙?))

具体实现(九宫格法)
把一个窗体划分为9个部分如图
这里写图片描述
图2 九宫格
鼠标位于22区域代表移动,位于其他位置代表拖动

首先设置窗体属性

    setWindowFlags(Qt::FramelessWindowHint);  //无边框
    //如果启用了鼠标跟踪,即使没有按下按钮,控件也会接收到鼠标移动事件。
    setMouseTracking(true);                   
    setMinimumSize(50,50);
  • 实现鼠标进入相应的区域,鼠标的样式改变

鼠标样式有很多种类可以通过帮助文档的enum Qt::CursorShape枚举类型查看
主要使用的有
这里写图片描述

    int     row(QPointF pos);         //计算九宫格行
    int     col(QPointF pos);         //计算九宫格列
    int     moveArea(QPointF pos);    //点击区域 相对于九宫格
    void    setMouseStyle(int moveArea);

前三个函数比较简单,这里给出源码

//其中m_nBorder是边界长度 也就是 九宫格中边缘的行和列宽度
int Widget::row(QPointF pos)
{
    if(pos.y() < m_nBorder)
    {
        return 10;
    }
    else if(pos.y() > height() - m_nBorder)
    {
        return 30;
    }
    else
    {
        return 20;
    }
}

int Widget::col(QPointF pos)
{
    if(pos.x() < m_nBorder)
    {
        return 1;
    }
    else if(pos.x() > width() - m_nBorder)
    {
        return 3;
    }
    else
    {
        return 2;
    }
}

int Widget::moveArea(QPointF pos)
{
    return row(pos) + col(pos);
}

当鼠标MoveEvent事件触发时,设置鼠标样式,具体代码如下

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    setMouseStyle(moveArea(event->pos()));
}

void Widget::setMouseStyle(int moveArea)
{
    switch (moveArea) {
    case 11:
        setCursor(Qt::SizeFDiagCursor);
        break;
    case 12:
        setCursor(Qt::SizeVerCursor);
        break;
    case 13:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case 21:
        setCursor(Qt::SizeHorCursor);
        break;

    case 22:
        if(!m_bPress)
        {
            setCursor(Qt::OpenHandCursor);
        }
        break;
    case 23:
        setCursor(Qt::SizeHorCursor);
        break;
    case 31:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case 32:
        setCursor(Qt::SizeVerCursor);
        break;
    case 33:
        setCursor(Qt::SizeFDiagCursor);
        break;

    default:
        setCursor(Qt::WaitCursor);
        break;
    }
}

通过以上设置即可实现鼠标进入窗体时,鼠标样式改变!

  • 移动实现
    移动实现的方法就是当前坐标和上一次坐标的差值作为窗体移动的变量
    实现代码如下
//变量声明
bool    m_bPress;        //左鼠标点击实现移动
QPoint  m_currentPos;   //屏幕上点击的坐标点
void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::LeftButton)
    {
        m_bPress = true;
        m_currentPos = event->globalPos();
    }
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
  if(m_bPress)
    {
        QPoint tempPos = event->globalPos() - m_currentPos;
        move(pos() + tempPos);
        m_currentPos = event->globalPos();
    }
}

即可实现移动效果
这里写图片描述
图3 移动

  • 最后实现拖拽效果
    下面给出关键实现代码
      QPoint tempPos = event->globalPos() - m_currentPos;
            QRect rect=geometry();                                //记录窗体当前位置
            //鼠标左键处于拖拽拉伸区域
            switch(m_flag)   //m_flag为鼠标点击左键时  鼠标样式状态
            {
            case 11:
                rect.setTopLeft(rect.topLeft()+tempPos);          //左上角
                break;

            case 13:
                rect.setTopRight(rect.topRight()+tempPos);        //右上角
                break;

            case 31:
                rect.setBottomLeft(rect.bottomLeft()+tempPos);    //左下角
                break;

            case 33:
                rect.setBottomRight(rect.bottomRight()+tempPos);  //右下角
                break;

            case 12:
                rect.setTop(rect.top()+tempPos.y());              //上
                break;

            case 21:
                rect.setLeft(rect.left()+tempPos.x());            //左
                break;

            case 23:
                rect.setRight(rect.right()+tempPos.x());          //右
                break;

            case 32:
                rect.setBottom(rect.bottom()+tempPos.y());        //下
                break;
            default:
                break;
            }
            this->setGeometry(rect);
        }

通过以上步骤即可实现一个无边框的窗体移动、拖拽。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值