玩转Qml(11)-更强的拖动组件

gallery-img

简介

本文是《玩转Qml》系列文章的第十一篇,之前的<玩转Qml(2)-可以拖动的组件>分享过基本的

拖动组件,这次涛哥将教大家,实现更多功能的可拖动组件。

源码

《玩转Qml》系列文章,配套了一个优秀的开源项目:TaoQuick

github https://github.com/jaredtao/TaoQuick

访问不了或者速度太慢,可以用国内的镜像网站gitee

https://gitee.com/jaredtao/TaoQuick

效果图

 

1

使用

封装的组件名称是TemplateBorder。

使用很简单,在要支持拖拽的目标组件上,创建一个TemplateBorder实例即可,例如:

Rectangle {
    x: 100
    y: 200
    width: 300
    height: 200
    color: "red"
    smooth: true
    antialiasing: true
    MouseArea {
        anchors.fill: parent
        onClicked: {
            parent.focus = true
        }
    }
    //这里添加一个边框
    TemplateBorder {
        //注意控制大小
        width: parent.width + borderMargin * 2
        height: parent.height + borderMargin * 2
        anchors.centerIn: parent
        //目标item有焦点时显示边框
        visible: parent.focus
    }
}

原理

拖拽的前提

目标组件不要用锚布局,不要用Layout布局。

拖拽需要修改目标组件的坐标和宽高,而锚布局、Layout会限定坐标或宽高。

拖拽原理

拖拽本身可以使用MouseArea的 drag.target,但这个target限制为item及其子类。

有时候还需要处理无边框窗口的拖动,窗口不是item,就不能用drag.target。

所以需要一个通用的拖拽算法:

...
MouseArea {
    id: mouseArea
    anchors.fill: parent
    property int lastX: 0
    property int lastY: 0
    onPressedChanged: {
        if (containsPress) {
          //按下鼠标时记录坐标
            lastX = mouseX;
            lastY = mouseY;
        }
    }
    onPositionChanged: {
        if (pressed) {
          //拖动时修改目标的坐标
            parent.x += mouseX - lastX
            parent.y += mouseY - lastY
        }
    }
}
...

锚点

锚点就是在组件的左上角、右上角等八个点,分别放一个小圆圈,圆圈里面是可拖拽组件,分别控制组件的坐标、宽高。

注意每个点的计算规则都不太一样。

例如左上角,要同时计算x、y和宽高,而右上角则只计算y、和宽高:

Item {
    id: root
    //controller 要控制大小的目标,可以是Item,也可以是view,只要提供x、y、width、height等属性的修改
    //默认值为parent
    property var control: parent
    //左上角的拖拽
    TDragItem {
        id: leftTopHandle
        posType: posLeftTop
        onPosChange: {
            if (control.x + xOffset < control.x + control.width)
                control.x += xOffset;
            if (control.y + yOffset < control.y + control.height)
                control.y += yOffset;
            if (control.width - xOffset > 0)
                control.width-= xOffset;
            if (control.height -yOffset > 0)
                control.height -= yOffset;
        }
    }
    //右上角拖拽
    TDragItem {
        id: rightTopHandle
        posType: posRightTop
        x: parent.width - width
        onPosChange: {
            //向左拖动时,xOffset为负数
            if (control.width + xOffset > 0)
                control.width += xOffset;
            if (control.height - yOffset > 0)
                control.height -= yOffset;
            if (control.y + yOffset < control.y + control.height)
                control.y += yOffset;
        }
    }
    ...
    ...
}

旋转

旋转算法和拖拽类似

MouseArea {
    id: rotateArea
    anchors.centerIn: parent
    property int lastX: 0

    onPressedChanged: {
      if (containsPress) {
        lastX = mouseX;
      }
    }
    onPositionChanged: {
      if (pressed) {
        let t = controller.rotation +(mouseX - lastX) / 5
        //这里的除以5,用来消除抖动。
        t = t % 360
        controller.rotation = t
      }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jared2020

你的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值