玩转Qml(11)-更强的拖动组件
本文于
1038
天之前发表,文中内容可能已经过时。
简介
本文是《玩转Qml》系列文章的第十一篇,之前的<玩转Qml(2)-可以拖动的组件>分享过基本的
拖动组件,这次涛哥将教大家,实现更多功能的可拖动组件。
源码
《玩转Qml》系列文章,配套了一个优秀的开源项目:TaoQuick
github https://github.com/jaredtao/TaoQuick
访问不了或者速度太慢,可以用国内的镜像网站gitee
https://gitee.com/jaredtao/TaoQuick
效果图
使用
封装的组件名称是TemplateBorder。
使用很简单,在要支持拖拽的目标组件上,创建一个TemplateBorder实例即可,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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 visible: parent.focus } }
|
原理
拖拽的前提
目标组件不要用锚布局,不要用Layout布局。
拖拽需要修改目标组件的坐标和宽高,而锚布局、Layout会限定坐标或宽高。
拖拽原理
拖拽本身可以使用MouseArea的 drag.target,但这个target限制为item及其子类。
有时候还需要处理无边框窗口的拖动,窗口不是item,就不能用drag.target。
所以需要一个通用的拖拽算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ... 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、和宽高:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Item { id: root 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: { 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; } } ... ... }
|
旋转
旋转算法和拖拽类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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 } } }
|