[Solved] Is it possible to have two mouse areas process the same mouse event?
-
I want to have a popup overlay in my qml application. If you click outside of the popup overlay it needs to close the popup and send the mouse event to mouse area that would of received the event if the popup overlay was not visible.
Example code:
@
import QtQuick 1.0Rectangle {
width: 500;
height: 500;Rectangle {
id: r1;
anchors.fill: parent;
color: "slategray";MouseArea {
id: m1;anchors.fill: parent;
onClicked: {
console.log("m1 clicked " + mouse.x + ", " + mouse.y);
}
}
}Item {
id: popupOverlay;anchors.fill: parent;
MouseArea {
id: m3;anchors.fill: parent;
onClicked: {
console.log("m3 clicked " + mouse.x + ", " + mouse.y);// close popupOverlay and have m1 process the mouse event popupOverlay.visible = false;
}
}Rectangle {
id: r2;
anchors.fill: parent;
anchors.margins: 50;color: "black";
opacity: 0.5;MouseArea {
id: m2;
anchors.fill: parent;onClicked: { console.log("Don't close overlay"); }
}
}
}
}@
In that example I am only able to close the popup when m3 is clicked.
-
What if you define a function which process the events and call it from m3 and m1 clicked events?
-
This is just a small example, I have hundreds of mouse areas and about 10 popups. I would need to traverse the graphics stack to see what mouse areas are actually being drawn and then find which ones overlap the x, and y locations of the mouse event. Then I could call that functions. I was hoping I wouldn't have to do something like that.
I have implemented this with GTK by disabling the "mouse area" and re-sending the mouse event and then re-enabling the "mouse area". I was hoping qt quick already supported something like that.
-
Is it sufficient to make sure that the "accepted":http://doc.qt.nokia.com/4.7-snapshot/qml-mouseevent.html#accepted-prop property on the MouseEvent in the MouseArea handler is set to false so that the event propagates to other MouseAreas?
-
The accepted property of the MouseEvent parameter is ignored in this handler.
http://doc.qt.nokia.com/latest/qml-mousearea.html#onClicked-signal
Maybe only solution is to remove m3 mouse area and check in m1 onClicked if click was inside the overlay area and the overlay area was visible.
-
Related bug report https://bugreports.qt.nokia.com/browse/QTBUG-13007
-
[quote author="Diph" date="1314126601"] The accepted property of the MouseEvent parameter is ignored in this handler.
http://doc.qt.nokia.com/latest/qml-mousearea.html#onClicked-signal
Maybe only solution is to remove m3 mouse area and check in m1 onClicked if click was inside the overlay area and the overlay area was visible.[/quote]
onClicked is called after a onPressed and a onReleased, so if onPressed/onReleased doesn't accept the event, onClicked won't be called.
-
The visibility is a great way to pull this off. I have set multiple MouseAreas as the same area before in a project and just made them visible true or false when I needed them. The other thing you might think about doing is setting the z: . If you change the the one you want to be the top most to z: 3 than it should put it on top. Just an idea.
-
My Solution:
Created an EventFilter plugin, that installs an event filter on that instance of the qml element.
Plugin:
Added signals for mouse pressed (x, y) and mouse released (x, y).
Added a property to enable/disable the filter.QML:
In my QML I put an EventFilter element in all of my popup overlays.
When the overlay is visible I enable its associated EventFilter.
When the EventFilter gets the mouse pressed signal I see if the x and y are outside the overlay.
If the mouse press is outside the overlay I make the overlay not visible. -
would you like to share your code?
are there any better ways in Qt5?[quote author="bundickt" date="1314207209"]My Solution:
Created an EventFilter plugin, that installs an event filter on that instance of the qml element.
Plugin:
Added signals for mouse pressed (x, y) and mouse released (x, y).
Added a property to enable/disable the filter.QML:
In my QML I put an EventFilter element in all of my popup overlays.
When the overlay is visible I enable its associated EventFilter.
When the EventFilter gets the mouse pressed signal I see if the x and y are outside the overlay.
If the mouse press is outside the overlay I make the overlay not visible.[/quote] -
I haven't started using Qt 5, so I'm not sure if it does this.
This plugin is good for this and it's also good for implementing a screen saving feature.
Here is the plugin code:
@
#include <qdeclarative.h>
#include <QObject>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QBool>
#include <QApplication>
#include <QDebug>class QMLKeyEvent : public QObject {
Q_OBJECT
Q_PROPERTY(int key READ key)
Q_PROPERTY(QString text READ text)
Q_PROPERTY(int modifiers READ modifiers)
Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
Q_PROPERTY(int count READ count)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
Q_PROPERTY(int nativeScanCode READ nativeScanCode)
Q_PROPERTY(int type READ type)public:
QMLKeyEvent(const QKeyEvent &ke, const int n = 0) : _event(ke), _nativeScanCode(n) { _event.setAccepted((false)); }int key() const { return _event.key(); }
QString text() const { return _event.text(); }
int modifiers() const { return _event.modifiers(); }
bool isAutoRepeat() const { return _event.isAutoRepeat(); }
int count() const { return _event.count(); }
bool isAccepted() const { return _event.isAccepted(); }
void setAccepted(bool accepted) { _event.setAccepted(accepted); }
int nativeScanCode() const { return _nativeScanCode; }
int type() const { return _event.type(); }private:
QKeyEvent _event;
int _nativeScanCode;
};class QMLMouseEvent : public QObject {
Q_OBJECT
Q_PROPERTY(int x READ x)
Q_PROPERTY(int y READ y)
Q_PROPERTY(int globalX READ globalX)
Q_PROPERTY(int globalY READ globalY)
Q_PROPERTY(int button READ button)
Q_PROPERTY(int buttons READ buttons)
Q_PROPERTY(int modifiers READ modifiers)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)public:
QMLMouseEvent(const QMouseEvent &me) : _event(me) { _event.setAccepted(false); }int x() const { return _event.x(); }
int y() const { return _event.y(); }
int globalX() const { return _event.globalX(); }
int globalY() const { return _event.globalY(); }
int button() const { return _event.button(); }
int buttons() const { return _event.buttons(); }
int modifiers() const { return _event.modifiers(); }bool isAccepted() { return _event.isAccepted(); }
void setAccepted(bool accepted) { _event.setAccepted(accepted); }private:
QMouseEvent _event;
};QML_DECLARE_TYPE(QMLKeyEvent)
QML_DECLARE_TYPE(QMLMouseEvent)class UserEventFilter : public QObject
{
Q_OBJECTQ_PROPERTY(bool enabled READ getEnabled WRITE setEnabled NOTIFY enabledChanged)
public:
UserEventFilter(QObject * parent = 0);
virtual ~UserEventFilter();public: // for properties
bool getEnabled() const;
void setEnabled(const bool enabled);signals: // for properties
void enabledChanged(bool newEnabled);signals:
void userEventOccurred();void keyPressed(QMLKeyEvent *event);
void keyReleased(QMLKeyEvent *event);void mousePressed(QMLMouseEvent *event);
void mouseReleased(QMLMouseEvent *event);
void mouseMoved(QMLMouseEvent *event);private:
bool processKeyPress(QEvent *event);
bool processKeyRelease(QEvent *event);
bool processMouseButtonPress(QEvent *event);
bool processMouseButtonRelease(QEvent *event);
bool processMouseMove(QEvent *event);private: // for properties
bool _enabled;protected:
bool eventFilter(QObject * obj, QEvent * event);
};UserEventFilter::UserEventFilter(QObject * parent) : QObject(parent) {
_enabled = true;
qApp->installEventFilter(this);
}UserEventFilter::~UserEventFilter() {
}bool UserEventFilter::getEnabled() const {
return _enabled;
}void UserEventFilter::setEnabled(const bool enabled) {
if(_enabled != enabled) {
_enabled = enabled;
emit enabledChanged(_enabled);
}
}bool UserEventFilter::processKeyPress(QEvent *event) {
QKeyEvent *e = static_cast<QKeyEvent *>(event);
QMLKeyEvent ke(*e, e->nativeScanCode());ke.setAccepted(false);
emit keyPressed(&ke);
emit userEventOccurred();return ke.isAccepted();
}bool UserEventFilter::processKeyRelease(QEvent *event) {
QKeyEvent *e = static_cast<QKeyEvent *>(event);
QMLKeyEvent ke(*e, e->nativeScanCode());
ke.setAccepted(false);emit keyReleased(&ke);
emit userEventOccurred();return ke.isAccepted();
}bool UserEventFilter::processMouseButtonPress(QEvent *event) {
QMLMouseEvent me(*static_cast<QMouseEvent *>(event));
me.setAccepted(false);emit mousePressed(&me);
emit userEventOccurred();return me.isAccepted();
}bool UserEventFilter::processMouseButtonRelease(QEvent *event) {
QMLMouseEvent me(*static_cast<QMouseEvent *>(event));
me.setAccepted(false);emit mouseReleased(&me);
emit userEventOccurred();return me.isAccepted();
}bool UserEventFilter::processMouseMove(QEvent *event) {
QMLMouseEvent me(*static_cast<QMouseEvent *>(event));
me.setAccepted(false);emit mouseMoved(&me);
emit userEventOccurred();return me.isAccepted();
}bool UserEventFilter::eventFilter(QObject * obj, QEvent * event) {
Q_UNUSED(obj);if(_enabled) {
switch(event->type()) {
case QEvent::KeyPress:
return processKeyPress(event);
break;case QEvent::KeyRelease:
return processKeyRelease(event);
break;case QEvent::MouseButtonPress:
return processMouseButtonPress(event);
break;case QEvent::MouseButtonRelease:
return processMouseButtonRelease(event);
break;case QEvent::MouseMove:
return processMouseMove(event);
break;default:
break;
}
}return QObject::eventFilter(obj, event);
}@