QML學習筆記——自定義Rectangle控件之動態縮放

寫在前面

  • 之前需要用到一個可以動態拖拽、放大縮小的控件,在網上沒找到合適的“輪子”(o(╯□╰)o),於是自己動手造了一個^_^ 。

Rectangle

環境

  • Qt 5.9.3 + MinGW
  • window 10

設計思路

  • 思路比較簡單,就是仿照window窗口的拖拉,將Rectangle分成九宮格,如下圖:
    這裏寫圖片描述
    分別爲:

    LeftTop
    Top
    RightTop
    Left
    Center
    Right
    LeftBottom
    Bottom
    RightBottom

  • MouseArea獲取鼠標事件,計算座標,判斷其在哪個區域,並處理。

上代碼

  • step表示四周判斷距離,可以自行調整,(PS:矩形4個角的方塊的寬度)
> 四個角落的小方塊,是我爲了體現出判斷區域的大小用 `Canvas` 畫上去的。
    Canvas{
            id:can2d;
            contextType: "2d";
            anchors.fill: parent;

            onPaint: {
                context.fillStyle = "blue";
                context.fillRect(0,0,step,step);
                context.fillRect(0,block.height-step,step,step);
                context.fillRect(block.width-step,0,step,step);
                context.fillRect(block.width-step,block.height-step,step,step);
            }
    }
  • mouseState的值爲0~9,代表鼠標在MouseArea中的狀態,分別爲
mouseState Area
0 丟失焦點
1 LeftTop
2 Left
3 LeftBottom
4 Top
5 Center
6 Bottom
7 RightTop
8 Left
9 RightBottom
  • 關鍵代碼MouseArea
    hoverEnabled: block.focus;:只有在有焦點的時候才響應鼠標移動事件。
    mouseOld:在鼠標按下時記錄的起始座標。
    mouseNew:鼠標移動時的當前座標。
    isclicked:鼠標是否按下。(PS:block在有焦點且在鼠標按下的情況下,進行拖拽等事件;在有焦點,鼠標沒有按下時僅改變鼠標形狀。)
    cursorShape:設置鼠標形狀
    MouseArea {
        id:mouse_area;
        hoverEnabled: block.focus;
        anchors.fill: block;

        onPressed:{
            block.focus=true;
            block.isclicked=true;
            mouseOld=parent.mapToItem(parent.parent,mouseX,mouseY);

            mouse.accepted=true;
        }
        onReleased:{
            block.isclicked=false;
            mouse.accepted=true;
        }
        onPositionChanged: {
            if(block.isclicked)
            {
                mouseNew=parent.mapToItem(parent.parent,mouseX,mouseY);

                switch(mouseState)
                {
                case 0:
                case 5:
                    block.x=block.x+mouseNew.x-mouseOld.x;
                    block.y=block.y+mouseNew.y-mouseOld.y;
                    break;

                case 1:
                ...
                case 2:
                case 3:
                case 4:
                case 6:
                case 7:
                case 8:
                case 9:
                default:
                }

                //這裏的兩個if是限制block的最小尺寸,防止縮小到看不見。
                if(block.width<=25)
                    block.width=25;

                if(block.height<=25)
                    block.height=25;

                mouseOld=mouseNew;
            }
            else{
                if(mouseX<block.step&&mouseX>=0)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=1;
                        mouse_area.cursorShape= Qt.SizeFDiagCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=3;
                        mouse_area.cursorShape= Qt.SizeBDiagCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=2;
                        mouse_area.cursorShape= Qt.SizeHorCursor;
                    }
                }
                else if(block.width-block.step<mouseX&&mouseX<=block.width)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=7;
                        mouse_area.cursorShape= Qt.SizeBDiagCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=9;
                        mouse_area.cursorShape= Qt.SizeFDiagCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=8;
                        mouse_area.cursorShape= Qt.SizeHorCursor;
                    }
                }
                else if(block.width-block.step>=mouseX&&mouseX>=block.step)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=4;
                        mouse_area.cursorShape= Qt.SizeVerCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=6;
                        mouse_area.cursorShape= Qt.SizeVerCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=5;
                        mouse_area.cursorShape=Qt.ArrowCursor;
                    }
                }
            }
            mouse.accepted=true;
        }
    }
  • 完整代碼
import QtQuick 2.7
import QtQuick.Controls 2.0

Rectangle {
    id:block;
    width: 170;
    height: 100;

    property int step: 10;   //鼠標的檢測區域尺寸
    property var mouseOld;   //鼠標按下時的座標
    property var mouseNew;   //鼠標移動時的座標

    //是否點擊
    property bool isclicked: false;
    //鼠標狀態
    property int mouseState: 0;

    border.width: 2;
    border.color:"blue";
    color: block.focus ? "green" : "blue"

    //繪製4個角
    Canvas{
            id:can2d;
            contextType: "2d";
            anchors.fill: parent;

            onPaint: {
                context.fillStyle = "blue";
                context.fillRect(0,0,step,step);
                context.fillRect(0,block.height-step,step,step);
                context.fillRect(block.width-step,0,step,step);
                context.fillRect(block.width-step,block.height-step,step,step);
            }
    }

    MouseArea {
        id:mouse_area;
        hoverEnabled: block.focus;
        anchors.fill: block;

        onPressed:{
            block.focus=true;
            block.isclicked=true;
            mouseOld=parent.mapToItem(parent.parent,mouseX,mouseY);

            mouse.accepted=true;
        }
        onReleased:{
            block.isclicked=false;
            mouse.accepted=true;
        }
        onPositionChanged: {
            if(block.isclicked)
            {
                mouseNew=parent.mapToItem(parent.parent,mouseX,mouseY);

                switch(mouseState) //判斷鼠標當前狀態,0代表,在無焦點的情況下,直接點擊就可以拖動。
                {
                case 0:
                case 5:
                    block.x=block.x+mouseNew.x-mouseOld.x;
                    block.y=block.y+mouseNew.y-mouseOld.y;
                    break;

                case 1:
                    block.width=block.width-mouseNew.x+mouseOld.x;
                    block.height=block.height-mouseNew.y+mouseOld.y;
                    if(block.width>25)
                    block.x=block.x+mouseNew.x-mouseOld.x;
                    if(block.height>25)
                    block.y=block.y+mouseNew.y-mouseOld.y;
                    break;

                case 2:
                    block.width=block.width-mouseNew.x+mouseOld.x;
                    if(block.width>25)
                    block.x=block.x+mouseNew.x-mouseOld.x;
                    break;

                case 3:
                    block.width=block.width-mouseNew.x+mouseOld.x;
                    block.height=block.height+mouseNew.y-mouseOld.y;
                    if(block.width>25)
                    block.x=block.x+mouseNew.x-mouseOld.x;
                    break;

                case 4:
                    block.height=block.height-mouseNew.y+mouseOld.y;
                    if(block.height>25)
                    block.y=block.y+mouseNew.y-mouseOld.y;
                    break;

                case 6:
                    block.height=block.height+mouseNew.y-mouseOld.y;
                    break;

                case 7:
                    block.height=block.height-mouseNew.y+mouseOld.y;
                    block.width=block.width+mouseNew.x-mouseOld.x;
                    if(block.height>25)
                    block.y=block.y+mouseNew.y-mouseOld.y;
                    break;

                case 8:
                    block.width=block.width+mouseNew.x-mouseOld.x;
                    break;

                case 9:
                    block.width=block.width+mouseNew.x-mouseOld.x;
                    block.height=block.height+mouseNew.y-mouseOld.y;
                    break;
                default:

                }
                //這裏的兩個if是限制block的最小尺寸,防止縮小到看不見。
                if(block.width<=25)
                    block.width=25;

                if(block.height<=25)
                    block.height=25;

                mouseOld=mouseNew;
            }
            else
            {
                if(mouseX<block.step&&mouseX>=0)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=1;
                        mouse_area.cursorShape= Qt.SizeFDiagCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=3;
                        mouse_area.cursorShape= Qt.SizeBDiagCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=2;
                        mouse_area.cursorShape= Qt.SizeHorCursor;
                    }
                }
                else if(block.width-block.step<mouseX&&mouseX<=block.width)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=7;
                        mouse_area.cursorShape= Qt.SizeBDiagCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=9;
                        mouse_area.cursorShape= Qt.SizeFDiagCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=8;
                        mouse_area.cursorShape= Qt.SizeHorCursor;
                    }
                }
                else if(block.width-block.step>=mouseX&&mouseX>=block.step)
                {
                    if(0<=mouseY&&mouseY<block.step){
                        mouseState=4;
                        mouse_area.cursorShape= Qt.SizeVerCursor;
                    }
                    else if((block.height-block.step)<mouseY&&mouseY<=block.height){
                        mouseState=6;
                        mouse_area.cursorShape= Qt.SizeVerCursor;
                    }
                    else if(block.step<=mouseY&&mouseY<=block.height-block.step){
                        mouseState=5;
                        mouse_area.cursorShape=Qt.ArrowCursor;
                    }
                }
            }
            mouse.accepted=true;
        }
    }

//失去焦點時改變鼠標形狀,且將鼠標狀態重置爲0,(不然在使用中達不到理想效果)
    onFocusChanged: {
        if(!block.focus)
        {
            mouse_area.cursorShape=Qt.ArrowCursor;
            mouseState=0;
        }
    }
}

小結

  • mapToItem 保存的座標是相對於block的parent的相對座標。

    object mapToItem(Item item, real x, real y)
    將調用該方法的對象(C)的座標點(x,y),映射到參數item(D)的座標系統中,並返回一個映射之後的座標(point)。此時,參數x,y是指的C對象上的座標點。如果item參數是null值,座標點的值就是從QML視圖的根元素的座標系統映射出來的。

    具體可看該博客:https://blog.csdn.net/imtina/article/details/53670528

  • 這只是個基礎的代碼,可以在這個的基礎上修改或者增加內容來滿足實際需要。

知識共享許可協議
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

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