QT 自定义边框,可伸缩,延伸, 拖动

有时为了美观,会自己制作边框, 这就意味着,你完成上述功能,要实现三个功能:

<1>窗体可自由 伸缩. 可大可小.
<2>窗体可随着鼠标移动
<3>自己实现标题栏(包含 最小化,最大化,关闭)

那么就按照上述的顺序来讲解:

窗体可自由 伸缩. 可大可小:

1:有时你会发现,当鼠标放在边框边时 鼠标会有变化,(箭头向上,向下, 向左,向右, 左上.... )

思路:
计算出这9个区域的 Rect ,然后根据鼠标停放的 pos 在哪个位置, 来设置鼠标的形状
鼠标 设置 可查看 文档 QCursor,
代码如下:

enum LocaTion{top,bottom,left,right,left_top,left_bottm,right_top,right_botm,middle};

LocaTion site_flag;


void Widget::set_Cursor(QMouseEvent *event)
{

    int width = this->width();
    int height = this->height();

    QRect top_ =            QRect(pading, 0, width - pading * 2, pading);
    QRect bottom_ =         QRect(pading, height - pading, width - pading * 2,pading);
    QRect left_ =           QRect(0, pading, pading, height - pading * 2);
    QRect right_ =          QRect(width - pading, pading, pading,height - pading * 2);
    QRect top_left =        QRect(0, 0, pading, pading);
    QRect top_right =       QRect(width - pading, 0, pading, pading);
    QRect bottom_left =     QRect(0, height - pading, pading, pading);
    QRect bottom_right =    QRect(width - pading, height - pading, pading, pading);

    if(top_.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeVerCursor));  // 设置鼠标形状  上
        site_flag = top;
    }

    else if(bottom_.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeVerCursor));  // 设置鼠标形状  下
        site_flag = bottom;
    }
    else if(left_.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeHorCursor));  // 设置鼠标形状  左
        site_flag = left;
    }
    else if(right_.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeHorCursor));  // 设置鼠标形状  右
        site_flag = right;
    }
    else if (top_left.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeFDiagCursor));  // 设置鼠标形状 左上
        site_flag = left_top;

    }
    else if (top_right.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeBDiagCursor));  // 设置鼠标形状 右上
        site_flag = right_top;
    }
    else if (bottom_left.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeBDiagCursor));  // 设置鼠标形状 左下
        site_flag = left_bottm;
    }
    else if(bottom_right.contains(event->pos()))
    {
        this->setCursor(QCursor(Qt::SizeFDiagCursor));  // 设置鼠标形状 右下
        site_flag = right_botm;
    }
    else
    {
        this->setCursor(QCursor(Qt::ArrowCursor));
        site_flag =  middle;
    }

}
2:当鼠标发生变化时 进行,拖动
思路:
窗体有他的最小 height ,width , 当伸缩时 相对距离大于 他的最小 height 和 width 才允发生变化 

注意;
窗体的原点在左上角. 通过x() , y() 就可以获取,;通过 setx() ,sety()设置他的左上的的位置
void Widget::set_Stretch(QMouseEvent *event)
{

    QRect rect = this->rect();
    QPoint gloPoint = event->globalPos() ;
    QPoint  topLeft = mapToGlobal(rect.topLeft());
    QPoint bottomRight = mapToGlobal(rect.bottomRight());
    QPoint bottomLeft = mapToGlobal(rect.bottomLeft());
    QPoint topRight = mapToGlobal(rect.topRight());


   // 窗体的的最初大小
    QRect rMove(topLeft, bottomRight);

    switch (site_flag) {
    case left:
		/*右边框 x 座标减去 左边正在延伸的 x 座标 大于最小宽度的情况下,*/
        if (bottomRight.x() - gloPoint.x() > this->minimumWidth())     
        {
           /*
           	    因为窗体的原点在左上角, 你拖动的正好是 左边,有一个相同点 那就是左边,所以设置 setx() 就可以. 和setwidth() 没有关系的.
           */
           rMove.setX(gloPoint.x()); 
        }
        this->setGeometry(rMove);
        break;
    case top:
        if (bottomRight.y() - gloPoint.y() > this->minimumHeight())
        {
        	/*共同点: 上 设置 sety()*/
            rMove.setY(gloPoint.y());
        }
        this->setGeometry(rMove);
        break;
    case right:
        if (gloPoint.x() - bottomLeft.x() > this->minimumWidth())
        {
       		 /*和左上没有共同点,这个时候,就不能通过setx() 来设置了,  可以仔细想想. 原点不变, 延伸右边,可以设置他的宽度啊*/
            rMove.setWidth(gloPoint.x() - bottomLeft.x());
        }
        this->setGeometry(rMove);
        break;
    case bottom:
        if (gloPoint.y() - topRight.y() > this->minimumHeight())
        {
        	//和右边的思路一样
            rMove.setHeight(gloPoint.y() - topRight.y());
        }
        this->setGeometry(rMove);
        break;
    case left_top:
     	// 和上面的判断有点不一样,这快判断的是 相对距离小于 最小size 
     	//将左上 分为左边,上边两部分 
        if ((bottomRight.y() - gloPoint.y() <= this->minimumHeight()) )
        {
           // 当窗体缩小的时候, 高度小于窗体最小高度,  有可能这会的宽度还是大于最小width , 所以就有如下判断
            rMove.setX(topLeft.x()); 
            rMove.setHeight(this->height());  //你也可以 改成 this->minnumheight()
        }
        else if( (bottomRight.x() - gloPoint.x() <= this->minimumWidth()))
        {
             rMove.setWidth(this->minimumWidth());
             rMove.setY(gloPoint.y());
        }
        else
        {
        	// 左上就是原点, 所以设置就可以通过 setx sety
            rMove.setX(gloPoint.x());
            rMove.setY(gloPoint.y());

        }
        this->setGeometry(rMove);
        break;
    case right_top:
        if (bottomRight.y() - gloPoint.y()  <= this->minimumHeight())
        {
            rMove.setWidth(gloPoint.x() - topLeft.x());
            rMove.setY(topRight.y());
        }
        else if(( gloPoint.x() - bottomLeft.x()  <= this->minimumWidth()))
        {
            rMove.setWidth(this->minimumWidth());
            rMove.setY(gloPoint.y());
        }
        else
        {
       		 //和原点左上的 共同点, 上边,那么就可以用sety(),而右边 通过 setWidth
            rMove.setWidth(gloPoint.x() - topLeft.x());
            rMove.setY(gloPoint.y());
        }
        this->setGeometry(rMove);
        break;
    case left_bottm:

        if(bottomRight.x() - gloPoint.x() <= this->minimumWidth())
        {
            rMove.setWidth(this->minimumWidth());
            rMove.setHeight(gloPoint.y() - topLeft.y());
        }
        else if(gloPoint.y() - topLeft.y() <= this->minimumHeight())
        {
            rMove.setX(gloPoint.x());
            rMove.setHeight(this->minimumHeight());
        }
        else
        {
            rMove.setBottomLeft(gloPoint);
        }
        this->setGeometry(rMove);
        break;
    case right_botm:
        if( gloPoint.y() - topLeft.y()  <= this->minimumHeight())
        {
            rMove.setWidth(gloPoint.x()- topLeft.x());
            rMove.setHeight(this->minimumHeight());
        }
        else if(( gloPoint.x() - bottomLeft.x()  <= this->minimumWidth()))
        {
            rMove.setWidth(this->minimumWidth());
            rMove.setHeight(gloPoint.y()- topLeft.y());
        }
        else
        {
            rMove.setWidth(gloPoint.x()- topLeft.x());
            rMove.setHeight(gloPoint.y()- topLeft.y());
        }
        this->setGeometry(rMove);
        break;
    case middle:
		//当鼠标停放在中间的时候, 那么这个操作就是拖动. 
        window()->move(window()->pos() +  gloPoint - Current_Pos);
        Current_Pos = gloPoint;

    default:
        event->ignore();
        break;
    }
    HB->setContentsMargins(0,0,0,this->height()-30);

}

窗体可随着鼠标移动, 自己实现标题栏(包含 最小化,最大化,关闭)

上面的其实已经有了:
当鼠标停放在 middle 的区域,就是拖动了.
具体可看,标题栏制作,的博客,里面有讲解

https://blog.csdn.net/sinat_14854721/article/details/80243813

微信:yangsenhehe

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章