寫在前面
- 之前需要用到一個可以動態拖拽、放大縮小的控件,在網上沒找到合適的“輪子”(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.csdn.net/imtina/article/details/53670528
這只是個基礎的代碼,可以在這個的基礎上修改或者增加內容來滿足實際需要。
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。