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

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