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中的状态,分别为
mouseStateArea
0丢失焦点
1LeftTop
2Left
3LeftBottom
4Top
5Center
6Bottom
7RightTop
8Left
9RightBottom
  • 关键代码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 国际许可协议进行许可。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值