Combine 2 MouseAreas on GridView - qt

I have code like this:
GridView {
// ... declarations ...
model: theModel
delegate: MouseArea {
id: cellMouseArea
onClicked: // open the cell
}
MouseArea {
id: gridViewMouseArea
// here process horizontal mouse press/release actions
}
}
with a MouseArea defined in each delegate and an overall MouseArea covering my GridView. In the cellMouseArea I want to perform an open item action whereas in the gridViewMouseArea I want to implement mouseX handle to open/close a sidebar. However, the two MouseAreas do not work together. How can I carry it out?

You can exploit propagateComposedEvents:
If propagateComposedEvents is set to true, then composed events will
be automatically propagated to other MouseAreas in the same location
in the scene. Each event is propagated to the next enabled MouseArea
beneath it in the stacking order, propagating down this visual
hierarchy until a MouseArea accepts the event. Unlike pressed events,
composed events will not be automatically accepted if no handler is
present.
You can set the property to true on the GridView MouseArea. In this way click events are propagated to the MouseAreas in the delegates whereas the outer MouseArea can implement other behaviours such as drag or hoven.
Here is an example in which outer MouseArea defines drag property to slide in/out a Rectangle ( simulating your sidebar) and thanks to the propagateComposedEvents clicks are managed by the single delegates.
import QtQuick 2.4
import QtQuick.Window 2.2
ApplicationWindow {
width: 300; height: 400
color: "white"
Component {
id: appDelegate
Item {
width: 100; height: 100
Text {
anchors.centerIn: parent
text: index
}
MouseArea {
anchors.fill: parent
onClicked: {
parent.GridView.view.currentIndex = index
console.info("Index clicked: " + index)
}
}
}
}
Component {
id: appHighlight
Rectangle { width: 80; height: 80; color: "lightsteelblue" }
}
GridView {
anchors.fill: parent
cellWidth: 100; cellHeight: 100
highlight: appHighlight
focus: true
model: 12
delegate: appDelegate
MouseArea {
anchors.fill: parent
z:1
propagateComposedEvents: true // the key property!
drag.target: dragged
drag.axis: Drag.XAxis
drag.minimumX: - parent.width
drag.maximumX: parent.width / 2
onMouseXChanged: console.info(mouseX)
}
}
Rectangle{
id: dragged
width: parent.width
height: parent.height
color: "steelblue"
x: -parent.width
}
}

Related

MouseArea does not pass click to CheckBox

Take a look at this QML snipped:
import QtQuick 2.4
import QtQuick.Controls 2.4
Rectangle {
color: "blue"
width: 50
height: 50
CheckBox {
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
}
}
}
I want to add MouseArea over CheckBox so I can handle doubleclick. However no matter how and what I do CheckBox stops working (clicking it won't show checked mark) as soon as there is MouseArea over it.
What's wrong here?
You can programmatically toggle Qt Quick 2 CheckBox with AbstractButton.toggle(). Also, MouseArea propagateComposedEvents property works only with other MouseAreas and not with Qt Quick Controls QML types.
I don't know your use case so I add few possibilities below.
Signal connect() method
Easiest way to achieve toggling through MouseArea is to create signal chain by connecting MouseArea clicked to CheckBox clicked.
Rectangle {
anchors.centerIn: parent
color: "blue"
width: 50
height: 50
CheckBox {
id: checkBox
onClicked: toggle()
MouseArea {
id: mouseArea
anchors.fill: parent
}
Component.onCompleted: mouseArea.clicked.connect(clicked)
}
}
Note that double click always starts with a single click. If you want to catch double clicks with MouseArea you can e.g. use a Timer for preventing propagating clicks to CheckBox.
Rectangle {
anchors.centerIn: parent
color: "blue"
width: 50
height: 50
CheckBox {
id: checkBox
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
if (timer.running) {
return
}
checkBox.toggle()
timer.start()
}
Timer {
id: timer
interval: 250
repeat: false
}
}
}
}
If you want to support CheckBox's pressed visualization and/or if you want to use bigger MouseArea than the size of the CheckBox you can take a look into this answer of the question Can't click button below a MouseArea.

QML: Mouse wheel event propagation in ListView

Have strange situation with ListView scrolling on mouse wheel. Have Items structure similar to this:
MainAppWindow {
// Some zoomable map item
Map {
anchors.fill: parent
}
PopupMenu { // Simple Rectangle item
anchors.top: parent.top
width: 200
height: parent.height / 2
z: parent.z + 1
ListView {
anchors.fill: parent
clip: true
...
delegate: Item {
...
MouseArea {
anchors.fill: parent
onClick: {
someHandler()
}
}
}
}
}
}
ListView with vertical scroll works and scrolls just fine until it stops at bounds (top or bottom - whatever) and after this mouse event starts to propagate to underlying layer and ZoomableMap starts to zoom which is not we want: should be propagated there only if PopupMenu is not visible. Adding
onWheel: wheel.accepted = true
into MouseArea inside ListView delegate could partially solve the problem - it disables wheel and allows scrolling only by dragging the content. However better allow scrolling by the wheel as well. MouseArea in PopupMenu blocks wheel and dragging in the ListView completely as well - not helps also.
So what is problem here, how to fix? Or we doing something wrong here?
Need to add another MouseArea into PopupMenu which blocks all mouse events and is disabled by default and enable it only if popup is visible (optional):
enabled: popupMenu.visible
MainAppWindow {
// Some zoomable map item
Map {
id: map
anchors.fill: parent
}
PopupMenu { // Simple Rectangle item
id: popupMenu
anchors.top: parent.top
width: 200
height: parent.height / 2
z: parent.z + 1
MouseArea {
id: mapMouseArea
anchors.fill: parent
enabled: popupMenu.visible
preventStealing:true
hoverEnabled: true
onWheel: { wheel.accepted = true; }
onPressed: { mouse.accepted = true; }
onReleased: { mouse.accepted = true; }
}
ListView {
anchors.fill: parent
clip: true
...
delegate: Item {
...
MouseArea {
anchors.fill: parent
onClick: {
someHandler()
}
}
}
}
}
}
Note: however this solution does not work if ListView (or any other control) is a Map descendant item: item dragging causes map panning. To make it work need to make it at least sibling.

in Qt How to enable ListView and its item all receive MouseArea events?

I'm using Qt 5.6
I want ListView and its items all receive MouseArea onEntered, onClicked signals.
I tried the examples and changed:
ListView {
anchors.fill: parent
model: searchModel
delegate: Component {
Row {
spacing: 5
Marker { height: parent.height }
Column {
Text { text: title; font.bold: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: console.log("eeee");
}
}
Text { text: place.location.address.text }
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: console.log("entered");
}
}
Only ListView can accept onEntered signal, there is no response from its items.
How to enable items receive MouseArea events ?
To propagate clicked events, you should set propagateComposedEvent to true to the outermost MouseArea.
Guess if the same applies to the entered event.

How to make double MouseArea take effect?

Here is my QML code :
Rectangle
{
.....
Rectangle
{
....height and width is smaller than parent
MouseArea
{
id: mouseArea2
anchors.fill: parent
hoverEnabled: true
onEntered:
{
console.log("enter 2")
}
}
}
MouseArea
{
id: mouseArea1
anchors.fill: parent
hoverEnabled: true
onEntered:
{
console.log("enter 1")
}
}
}
Only mouseArea1 takes effect. If I remove mouseArea1 then mouseArea2 takes effect. So I think the mouse event must be handled by mouseArea1 and let it couldn't be passed to mouseArea2.
I search the document to find out which attr can prevent such behavior but nothing found. So how to let the mouseArea1 and mouseArea2 take effect at the same time?
For "composed" mouse events -- clicked, doubleClicked and pressAndHold -- you can achieve this using the propagateComposedEvents property. But that won't work here because hover events are not composed events.
So what you need to do instead is to change the order in which the MouseAreas are evaluated.
One simple trick is to swap the order of the two MouseAreas in the QML source itself. By placing the smaller one after the larger one, the smaller one takes precedence:
Rectangle{
//.....
MouseArea{
id: mouseArea1
anchors.fill: parent
hoverEnabled: true
onEntered:{
console.log("enter 1")
}
}
Rectangle{
//....height and width is smaller than parent
MouseArea{
id: mouseArea2
anchors.fill: parent
hoverEnabled: true
onEntered:{
console.log("enter 2")
}
}
}
}
A second method that achieves the same thing is to add a z index to the topmost MouseArea that's greater than the lower one. By default every element has a z index of 0, so just adding z: 1 to the smaller MouseArea will do the trick:
Rectangle{
//.....
Rectangle{
//....height and width is smaller than parent
MouseArea{
z: 1 // <-----------------
id: mouseArea2
anchors.fill: parent
hoverEnabled: true
onEntered:{
console.log("enter 2")
}
}
}
MouseArea{
id: mouseArea1
anchors.fill: parent
hoverEnabled: true
onEntered:{
console.log("enter 1")
}
}
}
I have found the solution in the documentation. Take for instance the following QML code:
import QtQuick 2.0
Rectangle {
color: "yellow"
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: console.log("clicked yellow")
}
Rectangle {
color: "blue"
width: 50; height: 50
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onClicked: {
console.log("clicked blue")
mouse.accepted = false
}
}
}
}
Here the yellow Rectangle contains a blue Rectangle. The latter is the top-most item in the hierarchy of the visual stacking order; it will visually rendered above the former.
Since the blue Rectangle sets propagateComposedEvents to true, and also sets MouseEvent::accepted to false for all received clicked events, any clicked events it receives are propagated to the MouseArea of the yellow rectangle beneath it.
Clicking on the blue Rectangle will cause the onClicked handler of its child MouseArea to be invoked; the event will then be propagated to the MouseArea of the yellow Rectangle, causing its own onClicked handler to be invoked.

qml listview improve speed of changing items

i have a listview, how to change a speed of changing items, tried highlightMoveSpeed(highlightMoveDuration), but that does not working
Is there any way to increase the spped
slider.qml
import QtQuick 1.0
Rectangle {
id: slider
anchors.fill: parent
Component {
id: pageDelegate
Rectangle {
id: page
height: parent.height
Component.onCompleted: page.width = slider.width
Rectangle {
anchors.fill: parent
// anchors.margins: 15
Image{
anchors.top: parent.top
anchors.fill: parent
source: modelData
}
}
}
}
ListView {
id: list_model
anchors.fill: parent
model: modelData
delegate: pageDelegate
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
spacing: 5
highlightMoveSpeed: 10000000
}
}
You can either use the default highlight and set its speed, e.g.
highlightMoveDuration : 200
highlightMoveVelocity : 1000
or, in case you use your custom highlight, let the highlight component handle the behaviour. E.g.
// Set the highlight delegate. Note we must also set highlightFollowsCurrentItem
// to false so the highlight delegate can control how the highlight is moved.
highlightFollowsCurrentItem: false
highlight: Rectangle {
y: myListView.currentItem.y;
Behavior on y {
SmoothedAnimation {
easing.type: Easing.Linear
duration:200;
maximumEasingTime:300
velocity : 1000
}
}
}
Check the qt highlight example
A note about the other highlight move property: if you want to use highlightMoveDuration instead of highlightMoveVelocity (highlightMoveSpeed in Qt 4), you need to set the latter to -1:
highlightMoveDuration: 1000
highlightMoveVelocity: -1

Resources