Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

MouseArea hides ChartView Series signals



  • Hello! I have moved my topic from general questions here.

    I have faced with the following issue: ChartView has several Series (LineSeries and ScatterSeries in my case) and this series have signals that I want to process. Everything has been okay (I cat catch this signals and process) till I added MouseArea over ChartView to process different mouse and keyboards inputs. So my structure is something like this:

    ChartView {
         MouseArea {
            id: mouseAreaIntensity
            anchors.fill: parent
            acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
            propagateComposedEvents: true
            hoverEnabled: true
         }
    }
    

    In this case my series don't emit any signals (onHovered, onClicked, etc). I have supposed that propagateComposedEvents property let me do this, but this try was failed. How can I solve this issue?

    Thank you in advance!



  • 'MouseArea' composed events include "Clicked", "DoubleClicked" and "PressAndHold" [ONLY]. Hover is not considered to be a composed event (Correct me if I am wrong).

    One other important point to look at is the "OnClicked" function for "MouseArea" and "PieSeries/LineSeries". Here I considered the example of "PieSeries"

    MouseArea -> "onClicked(mouse)"
    PieSeries -> "onClicked(slice)"

    so there is a difference in the meaning of the function arguments.

    "propagateCompositeEvents" parameter when set "TRUE" works as expected.

    Sample Code can be checked below where the mouse right click is used by the "MouseArea" and mouse left click is propagated to the "PieSeries" as expected.

        ChartView
        {
            title: "Charts"
            anchors.fill: parent
            antialiasing: true
            id: seriesChart
            theme: ChartView.ChartThemeLight
    
            MouseArea
            {
                id: chartMouseArea
                anchors.fill: parent
                propagateComposedEvents: true
                acceptedButtons: Qt.RightButton
                onClicked:
                {
                    console.log("Mouse Area Clicked")
                }
                hoverEnabled: false
            }
    
            PieSeries {
                id: pieSeriesChart
                property int sliceIndex : 0
                PieSlice { label: "First Pie"; value: 45; onClicked: { pieSeriesChart.sliceIndex = 0; console.log("First Pie Clicked");} }
                PieSlice { label: "Second Pie"; value: 270; onClicked: { pieSeriesChart.sliceIndex = 1; console.log("Second Pie Clicked");} }
                PieSlice { label: "Third Pie"; value: 45; onClicked: { pieSeriesChart.sliceIndex = 2; console.log("Third Pie Clicked");}  }
                onClicked:
                {
                    for(var i = 0; i < pieSeriesChart.count; i++)
                        pieSeriesChart.at(i).exploded = false
                    pieSeriesChart.at(sliceIndex).exploded = true
                    console.log("PieSeries Clicked")
                }
                onHovered:
                {
                    console.log("Pie Slice Hovered")
                }
            }
        }
    

    Debug Log:

    qml: Pie Slice Hovered
    qml: Mouse Area Clicked
    qml: Pie Slice Hovered
    qml: Third Pie Clicked
    qml: PieSeries Clicked
    qml: Pie Slice Hovered
    qml: First Pie Clicked
    qml: PieSeries Clicked
    qml: Pie Slice Hovered
    

    Reference Image:

    Saa2.png



  • @jay1 Thank you again for your replies! I have tested your code and it's working well, but not exactly what I need. Can I use only one certain button to detect both events? I mean clicking left button leads to MouseArea and PieSeries onClicked events. Otherwise, if I could choose button for Series clicking event (e.g. Middle button), it would be nice too.

    I have also noticed that onHovered event is working well (over mouseArea and Series).



  • @St-Stanislav I have a similar issue. I have the MouseArea setup to pass events but in my case a QScatterSeries is not picking up what should be a propaged onClicked. Were you able to resolve?



  • @rhb327 Wouldnt you set the accepted flag in the mousearea event based upon if you consumed that event or not?

    MouseArea {
        onClicked: {
            var consumed = condition; // some condition
            if(consumed)
                mouse.accepted = true
            else
                mouse.accepted = false // will propagate event to underlying items
        }
    }
    


  • @fcarney yeah, that's what I'm trying to do...here's my mousearea:

     MouseArea {
                    anchors.fill: chartView
                    propagateComposedEvents: true
                    property int lastX: 0
                    property int lastY: 0
                    acceptedButtons: Qt.AllButtons
    
                    onClicked: {
                        console.log("YADA1")
                        mouse.accepted = false
                    }
                    onReleased: {
                        if (mouse.button === Qt.LeftButton) {
                            rep_iconOverLay.model=0
                            if (lastX !== mouse.x) {
                                chartView.scrollRight(lastX - mouse.x);
                                lastX = mouse.x;
                            }
                            if (lastY !== mouse.y) {
                                chartView.scrollDown(lastY - mouse.y);
                                lastY = mouse.y;
                            }
                            rep_iconOverLay.model=chartView.alarmTimeData
                        }
                        else if (mouse.button === Qt.RightButton) {
                            rep_iconOverLay.model=0
                            chartView.zoomIn(Qt.rect(zoomRect.x, zoomRect.y, zoomRect.width, zoomRect.height));
                            zoomRect.visible = false
                            chartView.pressed=false
                            rep_iconOverLay.model=chartView.alarmTimeData
                        }
                        mouse.accepted = true
                    }
                    onDoubleClicked: {
                        rep_iconOverLay.model=0
                        chartView.zoomReset()
                        timeAxis.min = xMinn
                        timeAxis.max = xMaxx
                        tempAxis.min = yMinn
                        tempAxis.max = yMaxx
                        rep_iconOverLay.model=chartView.alarmTimeData
                        mouse.accepted = true
                    }
                    onPressed: {
                        if (mouse.button === Qt.LeftButton) {
                            lastX = mouse.x;
                            lastY = mouse.y;
                        }
                        else if (mouse.button === Qt.RightButton){
                            chartView.pressed = false
                            zoomRect.x = mouse.x
                            zoomRect.y = mouse.y
                            zoomRect.visible = true
                        }
                        mouse.accepted = false
                    }
                    onMouseXChanged: {
                        zoomRect.width = mouse.x - zoomRect.x;
                        mouse.accepted = true
                    }
                    onMouseYChanged: {
                        zoomRect.height = mouse.y - zoomRect.y;
                        mouse.accepted = true
                    }
                }
    
    

    But the series never seems to get the onClick!

     onClicked: {
                        console.log("YADA2")
                        toolTipAlarm.visible=true
                        var pnt = chartView.mapToPosition(point, scatterSeries)
                        toolTipAlarm.x = pnt.x
                        toolTipAlarm.y = pnt.y
    
                        var stepCount=0
                        for(var i=0 ;i<stepDataArray.length; ++i) {
                            if(parseFloat(stepDataArray[i]).toFixed(3)===point.x.toFixed(3)) {
                                stepCount = i
                                break
                            }
                        }
                        console.log("SDA:", stepDataArray, point.x.toFixed(3), stepCount)
                        toolTipAlarm.text = qsTrId("Step: ") + parseInt(stepCount+1) + " | " + point.x.toFixed(3)
                    }
                    onPressed: {
                        console.log("YADA3")
                    }
    


  • @rhb327 I think your onReleased is eating the event. I am not sure how you are going to handle 2 things at once. You are doing something in onReleased, but you also want the chart to do something.



  • I've seen example where one MouseArea passes onClicked to another so the same event runs in two handlers (below). My understanding is onPressed and onReleased are not part of composite events so only the onClicked should get passed on from my MouseArea. I've tried adding mouse.accepted = false in every handler in my MouseArea as well but no luck.

    Any thoughts about how one might implement a simple zoom (like in my MouseArea) and maintain ability for tooltips on series? That's really what I'm after. The C++ version of ChartView has some mouse events but not the QML. I was hoping to avoid sub-classing a ChartView in C++.

    Thanks again for inputs...this has been a bit head scratching for me!



  • Can you provide an ultra simple version that does not work and does zoom? I have a pie chart from above, but it won't zoom. I am using onWheel event of mousearea with other buttons disabled. It gets the event, but it wont zoom. onclick works fine in pieseries too.



  • Absolutely...not sure if I'm supposed to zip and upload or cut and paste here but I think this shows my issue reasonably well. I hope it's short enough.

    import QtQuick 3.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.5
    import QtCharts 2.3
    
    Window {
        visible: true
        width: 640
        height: 480
    
        Rectangle {
            id: chartDataRect
            anchors.fill: parent
            //anchors{left: parent.left; leftMargin: 30; right: parent.rigth; rightMargin: 10; top: parent.top; topMargin: 40}
            //radius: 6
            width: 640
            height: 480
            color: "#ECEEEE"
    
            Component.onCompleted: {
                scatterSeries.append(1,2)
                scatterSeries.append(2,4)
                scatterSeries.append(4,7)
            }
    
            ChartView {
                id: chartView
                clip: true
                anchors.fill: parent
                legend.visible: false
                antialiasing: true
                legend.alignment:  Qt.AlignBottom
                backgroundColor: "#000000"
                theme: ChartView.ChartThemeDark
                width: 2.0
                property bool pressed: false
    
                ValueAxis {
                    id: timeAxis
                    color: "#344550"
                    min: 0
                    max: 10
                    labelFormat:"%.1f"
                    labelsColor: "#FFFFFF"
                }
    
                ValueAxis {
                    id: tempAxis
                    min: 0
                    max: 10
                    color: "#344550"
                    labelFormat:"%.1f"
                    labelsColor: "#FFFFFF"
                }
    
                ScatterSeries {
                    id: scatterSeries
                    axisX: timeAxis
                    axisY: tempAxis
                    color: "red"
                    visible: true
    
                    // TODO:  Still not working?  MouseArea does not seem to propagate (hover will work).
                    onClicked: {
                        console.log("Click Series")
                    }
                }
    
                MouseArea {
                    anchors.fill: chartView
                    propagateComposedEvents: true
                    //preventStealing: true
                    property int lastX: 0
                    property int lastY: 0
                    acceptedButtons: Qt.LeftButton | Qt.RightButton
    
                    onClicked: {
                        console.log("Click MouseArea")
                        mouse.accepted = false
                    }
                    onPressed: {
                        console.log("Press MouseArea")
                        if (mouse.button === Qt.LeftButton) {
                            lastX = mouse.x;
                            lastY = mouse.y;
                        }
                        else if (mouse.button === Qt.RightButton){
                            chartView.pressed = false
                            zoomRect.x = mouse.x
                            zoomRect.y = mouse.y
                            zoomRect.visible = true
                        }
                        mouse.accepted = true
                    }
                    onReleased: {
                        console.log("Released MouseArea")
                        if (mouse.button === Qt.LeftButton) {
                            if (lastX !== mouse.x) {
                                chartView.scrollRight(lastX - mouse.x);
                                lastX = mouse.x;
                            }
                            if (lastY !== mouse.y) {
                                chartView.scrollDown(lastY - mouse.y);
                                lastY = mouse.y;
                            }
                        }
                        else if (mouse.button === Qt.RightButton) {
                            chartView.zoomIn(Qt.rect(zoomRect.x, zoomRect.y, zoomRect.width, zoomRect.height));
                            zoomRect.visible = false
                            chartView.pressed=false
                        }
                    }
                    onDoubleClicked: {
                        console.log("Double Click MouseArea")
                        chartView.zoomReset()
                        timeAxis.min = 0
                        timeAxis.max = 10
                        tempAxis.min = 0
                        tempAxis.max = 10
                    }
                    onMouseXChanged: {
                        console.log("X Change MouseArea")
                        zoomRect.width = mouse.x - zoomRect.x;
                    }
                    onMouseYChanged: {
                        console.log("Y Change MouseArea")
                        zoomRect.height = mouse.y - zoomRect.y;
                    }
                }
    
                Rectangle{
                    id: zoomRect
                    color: "#FFFFFF"
                    opacity: 0.4
                    visible: false
                }
            }
        }
    }
    
    


  • If I change the onPressed event in mousearea to:

    //mouse.accepted = true
    mouse.accepted = false
    

    Then when I click on the red dots I get the "Click Series" message.

    Adding this to mousearea:

                   onWheel: {
                        var delta = wheel.angleDelta;
                        if(delta.y > 0){
                            chartView.zoomIn()
                        }else if(delta.y < 0){
                            chartView.zoomOut()
                        }
                    }
    

    Allows zoom in and out. I would also add keyboard +/- or something similar.



  • Ok...but when you did that zoom stopped working, right?



  • @rhb327 said in MouseArea hides ChartView Series signals:

    but when you did that zoom stopped working, right?

    Yes
    This works:

                       else if (mouse.button === Qt.RightButton){
                            chartView.pressed = false
                            zoomRect.x = mouse.x
                            zoomRect.y = mouse.y
                            zoomRect.visible = true
                            mouse.accepted = true
                            return
                        }
                        //mouse.accepted = true
                        mouse.accepted = false
    


  • Yes! Thank you.

    So I think my learning is that on the right click I need the accepted = true to ensure the released is handled in the same MouseArea for my zoom box. I'm not quite sure what to make in regard to the fact I passed clicked and pressed on via accepted = false. I would have thought I'd only need to pass along clicked. Thanks again.



  • @rhb327 I dont get it either. I think doing panning breaks too. I would put that on middle mouse button only. Maybe don't let that mousearea handle left clicks at all. It seems to be problematic.


Log in to reply