MouseArea in a Disabled QML element - qml

I have a widget that is widely used in my QML Application, it's enabled property has been used in most of the places to change it's view and disable it's actions. Let's say it is something like this
Item {
MouseArea {
anchors.fill: parent
onClicked: doSomething();
}
}
Now the problem is that we need to show a message when the button is disabled, but MouseArea will also be disabled when the parent is disabled. Is there any workaround for this to force the child to remain enabled?

Actually, the mouse area enabled property works differently from typical Items. It's really not disabled, but seems that way because the parent item is not enabled and thus cannot accept certain mouse events. To solve your problem just make the MouseArea a sibling.

Related

MouseArea in qml(onEntered, onExited, onReleased)

I have one button. I want to change the states of button e.g:
Default image is black.
onEntered i want image as blue, onExited i want image as black(equal to default state), and onReleased i want image as blue(equal to onEntered state).
Note:
onRelease should be active inside the button and outside the button onRelease shouldn't work.
How this can be achieved?
Mouse area looks like this:
MouseArea
{
anchors.fill: firstImage(parent)
onEntered:
{
firstImage.source = "blue.img"
}
onExited:
{
firstImage.source = "black.img"
}
onReleased:
{
firstImage.source = "blue.img"
}
}
Problem i am facing is:
onRelease is active outside the button.
I want onRelease to be active when press is released inside the button.
You can leverage the fact that you can give every object in qml an extra custom property.
I came up with the following, which seems to be what you ask, however, I see a flaw, because when you are 'entered' and press, the button will go to entered state, so there is not difference in the 'released' state, and after leaving the MouseArea it will again go to 'exited' state.
Note, I did not copy the firstImage.source stuff, but you can easily tailor this example to your situation
import QtQuick.Controls 2.4
Button {
hoverEnabled: true
property bool touched : false
onHoveredChanged: touched = hovered
onReleased: touched = true
text: touched ? "touched" : "not touched"
}
The hoverEnabled needs to be set

Querying global mouse position in QML

I'm programming a small PoC in QML. In a couple of places in my code I need to bind to/query global mouse position (say, mouse position in a scene or game window). Even in cases where mouse is outside of MouseAreas that I've defined so far.
Looking around, the only way to do it seems to be having whole screen covered with another MouseArea, most likely with hovering enabled. Then I also need to deal with semi-manually propagating (hover) events to underlying mouseAreas..
Am I missing something here? This seems like a pretty common case - is there a simpler/more elegant way to achieve it?
EDIT:
The most problematic case seems to be while dragging outside a MouseArea. Below is a minimalistic example (it's using V-Play components and a mouse event spy from derM's answer). When I click the image and drag outside the MouseArea, mouse events are not coming anymore so the position cannot be updated unless there is a DropArea below.
The MouseEventSpy is taken from here in response to one of the answers. It is only modified to include the position as parameters to the signal.
import VPlay 2.0
import QtQuick 2.0
import MouseEventSpy 1.0
GameWindow {
id: gameWindow
activeScene: scene
screenWidth: 960
screenHeight: 640
Scene {
id: scene
anchors.fill: parent
Connections {
target: MouseEventSpy
onMouseEventDetected: {
console.log(x)
console.log(y)
}
}
Image {
id: tile
x: 118
y: 190
width: 200
height: 200
source: "../assets/vplay-logo.png"
anchors.centerIn: parent
Drag.active: mausA.drag.active
Drag.dragType: Drag.Automatic
MouseArea {
id: mausA
anchors.fill: parent
drag.target: parent
}
}
}
}
You can install a eventFilter on the QGuiApplication, where all mouse events will pass through.
How to do this is described here
In the linked solution, I drop the information about the mouse position when emitting the signal. You can however easily retrieve the information by casting the QEvent that is passed to the eventFilter(...)-method into a QMouseEvent and add it as parameters to the signal.
In the linked answer I register it as singleton available in QML and C++ so you can connect to the signal where ever needed.
As it is provided in the linked answer, the MouseEventSpy will only handle QMouseEvents of various types. Once you start dragging something, there won't be QMouseEvents but QDragMoveEvents e.t.c. Therefore you need to extend the filter method, to also handle those.
bool MouseEventSpy::eventFilter(QObject* watched, QEvent* event)
{
QEvent::Type t = event->type();
if (t == QEvent::MouseButtonDblClick
|| t == QEvent::MouseButtonPress
|| t == QEvent::MouseButtonRelease
|| t == QEvent::MouseMove) {
QMouseEvent* e = static_cast<QMouseEvent*>(event);
emit mouseEventDetected(e->x(), e->y());
}
if (t == QEvent::DragMove) {
QDragMoveEvent* e = static_cast<QDragMoveEvent*>(event);
emit mouseEventDetected(e->pos().x(), e->pos().y());
}
return QObject::eventFilter(watched, event);
}
You can then translate the coordinates to what ever you need to (Screen, Window, ...)
As you have only a couple of places where you need to query global mouse position, I would suggest you to use mapToGlobal or mapToItem methods.
I believe you can get cursor's coordinates from C++ side. Take a look on answer on this question. The question doesn't related to your problem but the solution works as well.
On my side I managed to get global coordinates by directly calling mousePosProvider.cursorPos() without any MouseArea.

QML: ListView delegate: items vs. MouseArea

I have the following code:
ListView {
delegate: MyDelegate {
MouseArea {
anchors.fill: parent
/*some other stuff*/
}
}
}
The problem is that MyDelegate contains checkboxes and MouseArea "steals" mouse events from them. They do not react on mouse events at all, i.e. do not work as expected.
I know about propagateComposedEvents property of MouseArea...but I'll have to implement all of its mouse events (clicked, pressed, released,...) and check whether the mouse cursor is in the checkbox or not to set mouse.accepted property accordingly.
This is how I understood all of these currently. Is there any easier way, i.e. a way to be able to process all of the mouse events for areas that does not handle mouse events explicitly? For instance static text, progress bars, etc.
You can apply negative values to the z property of the MouseArea.
From the documentation:
Items with a higher stacking value are drawn on top of siblings with a lower stacking order. Items with the same stacking value are drawn bottom up in the order they appear. Items with a negative stacking value are drawn under their parent's content.

How to show current selection QML TreeView?

I can show current selection QML ListView but similar thing doesn't work in TreeView.
Part of the problem is for TreeView it doesn't recognize index which is passed to delegate in case of ListView. I tried styleData.indexbut that doesn't work either.
rowDelegate: Item {
id: row_delegate
height: 40
Rectangle {
id: rectid
anchors.fill: parent
MouseArea {
id: mouse_area
anchors.fill: parent
onClicked: {
console.log("Row clicked " + rectid.styleData.index)
}
}
}
}
The output is:
qml: Row clicked undefined
As stated by the documentation, you have a set of properties within the namespace styleData that can be used for almost the same purposes from within a delegate.
As an example, you can set the text property of a label that is part of your delegate as it follows:
text: styleData.value
Where styleData.value is (documentation excerpt):
the value or text for this item
Similarly, you have:
styleData.pressed - true when the item is pressed
styleData.index - the QModelIndex of the current item in the model
styleData.hasChildren - true if the model index of the current item has or can have children
And so on... Please, refer to the documentation for the full list.
Be aware also of the note at the end of the documentation:
Note: For performance reasons, created delegates can be recycled across multiple table rows. This implies that when you make use of implicit properties such as styleData.row or model, these values can change after the delegate has been constructed. This means that you should not assume that content is fixed whenComponent.onCompleted is called, but instead rely on bindings to such properties.

Zoom Flickable's content on wheel event

By default, Flickable scrolls on mouse wheel event: horizontally if Shift modifier is pressed, and vertically if no modifier is active. I'd like to override this behaviour to make it zoom in/out.
I tried to use MouseArea as a child of Flickable. Defining desired behaviour inside onWheel handler I get what I want, but it breaks flicking feature. Motion of two touch points is recognised as a wheel event on my Mac, what prevents Flickable to steel this event (MouseArea.preventSteeling is false by default). So I get somewhat mixed zooming feature that respects velocity/acceleration behaviour of Flickable.
Add an onWheel handler underneath your MouseArea:
MouseArea
{
onWheel: {
if (wheel.modifiers & Qt.ControlModifier){
if (wheel.angleDelta.y > 0)
{
zoomin()
}
else
{
zoomout()
}
}
else{
wheel.accepted=false
}
}
}