[SOLVED]QML mouse selection rectangle
-
Hi everyone,
just throwing this topic here in search of ideas if anyone has already stumbled on this matter.
I need to implement a mouse selection area in QML.
Something like this:
http://www.codeproject.com/KB/WPF/SimpleDragSelection/SimpleDragSelection1.pngI am inside a Flickable element containing a Canvas.
My idea is to do it with some drag&drop properties, showing and resizing a semi-transparent Rectangle as long as the mouse button is pressed.Is there any efficient way you can think of ?
Any help is greatly appreciated.
If I come up with a working solution soon, I will post it here.Thanks !
-
Adding one bit.
The Flickable item steals every mouse click.
I want the selection rectangle to be activated with the SHIFT key modifier only.
Is there a way to tell Flickable to ignore the mouse events if the SHIFT key is pressed ? -
OK, took me a couple of hours to implement it.
Here's the code. Might not be 100% perfect but it gives the idea:Rectangle { id: selectionRect visible: false x: 0 y: 0 z: 99 width: 0 height: 0 rotation: 0 color: "#5F227CEB" border.width: 1 border.color: "#103A6E" transformOrigin: Item.TopLeft } MouseArea { id: selectionMouseArea property int initialXPos property int initialYPos property bool justStarted anchors.fill: parent z: 2 // make sure we're above other elements onPressed: { if (mouse.button == Qt.LeftButton && mouse.modifiers & Qt.ShiftModifier) { console.log("Mouse area shift-clicked !") // initialize local variables to determine the selection orientation initialXPos = mouse.x initialYPos = mouse.y justStarted = true flickableView.interactive = false // in case the event started over a Flickable element selectionRect.x = mouse.x selectionRect.y = mouse.y selectionRect.width = 0 selectionRect.height = 0 selectionRect.visible = true } } onPositionChanged: { if (selectionRect.visible == true) { if (justStarted == true && (mouse.x != initialXPos || mouse.y != initialYPos)) { if (mouse.x >= initialXPos) { if (mouse.y >= initialYPos) selectionRect.rotation = 0 else selectionRect.rotation = -90 } else { if (mouse.y >= initialYPos) selectionRect.rotation = 90 else selectionRect.rotation = -180 } justStarted = false //console.log("Selection rotation: " + selectionRect.rotation) } if (selectionRect.rotation == 0 || selectionRect.rotation == -180) { selectionRect.width = Math.abs(mouse.x - selectionRect.x) selectionRect.height = Math.abs(mouse.y - selectionRect.y) } else { selectionRect.width = Math.abs(mouse.y - selectionRect.y) selectionRect.height = Math.abs(mouse.x - selectionRect.x) } } } onReleased: { selectionRect.visible = false // restore the Flickable duties flickableView.interactive = true } }
-
Now how the heck do I mark this thread as "solved" ?
Quoting:The ‘thread tools’ at the bottom of a thread let the poster or moderators ‘mark a thread as solved’. This will add a ‘Solved’ tag to the post in the category view to help people find solved posts easily.
The only option I have is "Delete topic"...nice...
-
In case you come across this a bit more complete example, including handling of contentY changing because of scroll...:
MouseArea
{id: selectionMouseArea
property alias selectionRect : selectionRect
property int initialXPos
property int initialYPos
property int mouseX
property int mouseY
anchors.fill: grid
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButtonRectangle {id: selectionRect visible: false x: 0 y: 0 z: 99 width: 0 height: 0 rotation: 0 radius: 5 color: "#5F227CEB" border.width: 1 border.color: "#103A6E" transformOrigin: Item.TopLeft } //selectionRect //moving close to top or bot end scrolls view depending on speed Timer {repeat: true;running: ( parent.mouseY < 0 && grid.contentY>0 ) && parent.pressed && !grid.atYBeginning; interval: 10; onTriggered: grid.contentY -= (-1 * parent.mouseY), returnToBounds() } Timer {repeat: true;running: ( parent.mouseY > grid.height) && parent.pressed && !grid.atYEnd interval: 10; onTriggered: grid.contentY += 1 * ( parent.mouseY -grid.height ), returnToBounds() } //makes the rectangle smooth Connections { target: grid onContentYChanged: //selectionRect needs to be depending onConentY as its size and position depends on that { if (selectionRect.rotation == 0 || selectionRect.rotation == -180) { selectionRect.y = selectionMouseArea.initialYPos - grid.contentY selectionRect.height = Math.abs(selectionMouseArea.mouseY - selectionMouseArea.initialYPos + grid.contentY) selectionRect.width = Math.abs(selectionMouseArea.mouseX - selectionRect.x) } else { selectionRect.y = selectionMouseArea.initialYPos - grid.contentY selectionRect.height = Math.abs(selectionMouseArea.mouseX - selectionRect.x) selectionRect.width = Math.abs(selectionMouseArea.mouseY - selectionRect.y) } } } onClicked: { if(mouse.button == Qt.RightButton) { mouse.accepted=false return; } if ( wasHeld || mouse.modifiers & Qt.ControlModifier ) return; initialXPos=mouse.x; initialYPos=mouse.y;mouseX=mouse.x;mouseY=mouse.y } onPressed: { if(mouse.button == Qt.RightButton) { mouse.accepted=false return; } if (mouse.modifiers & Qt.ControlModifier) { console.log("ControlModifier"); mouse.accepted=false return; } if (mouse.button == Qt.LeftButton) { initialXPos = mouse.x initialYPos = mouse.y+grid.contentY grid.interactive = false selectionRect.x = mouse.x selectionRect.y = mouse.y selectionRect.width = 0 selectionRect.height = 0 } if(itemAt(mouse.x,mouse.y+grid.contentY).hovered) mouse.accepted=false if(itemAt(mouse.x,mouse.y+grid.contentY).hovered===false) { ufm().resetSelection() grid.currentIndex=-1 } } onPositionChanged: { // console.log(selectionRect.height); // console.log(selectionRect.width); if(mouse.button == Qt.RightButton) { mouse.accepted=false return; } if (mouse.modifiers & Qt.ControlModifier) { return; } selectionRect.visible = true if (selectionRect.visible === false) { selectionRect.x = 0 selectionRect.y = 0 selectionRect.width = 0 selectionRect.height = 0 initialXPos = 0 initialYPos = 0 } if (selectionRect.visible === true) { mouseX = mouse.x mouseY = mouse.y if (Math.abs(mouseX, initialXPos)>30) wasHeld = true if (Math.abs(mouseY, initialYPos)>30) wasHeld = true if (mouse.x >= initialXPos) { if (mouse.y+grid.contentY >= initialYPos) selectionRect.rotation = 0 else selectionRect.rotation = -90 } else if (mouse.x <= initialXPos) { if (mouse.y+grid.contentY >= initialYPos) selectionRect.rotation = 90 else selectionRect.rotation = -180 } if (selectionRect.rotation == 0 || selectionRect.rotation == -180) { selectionRect.y = initialYPos - grid.contentY selectionRect.height = Math.abs(mouse.y - initialYPos + grid.contentY) selectionRect.width = Math.abs(mouse.x - selectionRect.x) } else { selectionRect.y = initialYPos - grid.contentY selectionRect.height = Math.abs(mouse.x - selectionRect.x) selectionRect.width = Math.abs(mouse.y - selectionRect.y) } } } onReleased: { selectionRect.visible = false // restore the Flickable duties grid.interactive = true } onWheel: { if (wheel.angleDelta.y > 0 && !grid.atYBeginning) grid.contentY -= 50 else if (wheel.angleDelta.y < 0 && !grid.atYEnd) grid.contentY += 50 }
}