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:
-
@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") }
-
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.
-
@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.