写在前面
- 之前需要用到一个可以动态拖拽、放大缩小的控件,在网上没找到合适的“轮子”(o(╯□╰)o),于是自己动手造了一个^_^ 。
环境
- 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.youkuaiyun.com/imtina/article/details/53670528
这只是个基础的代码,可以在这个的基础上修改或者增加内容来满足实际需要。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。