[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.png

    I 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...



  • Add [SOLVED] to the beginning of the subject line.



  • 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.RightButton

    Rectangle
    {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
    }
    

    }


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.