Jacob Krieg Jacob Krieg - 2 months ago 17
C++ Question

Make QML Item/Control accept events thus not forwarding them to parent

I inherited

QQuickWindow
and created a frame-less window that can be moved by drag. Inside my window I put a
Slider
element. The problem is that the
Slider
forwards the events to the parent window and when I try to change the value on the slider, the window moves along. Here's how it behaves:

enter image description here

Is there a possibility to make the slider accept the mouse events and not forward them to the window?

Here's my code:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QUrl>

#include "mywindow.h"

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

qmlRegisterType<MyWindow>("mycustomlib", 1, 0, "MyWindow");

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();
}


main.qml

import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import mycustomlib 1.0

MyWindow {
width: 300
height: 180
visible: true
x: 250
y: 250
color: "beige"

Slider {
anchors.fill: parent
value: 0.5
}
}


mywindow.h

#ifndef MYWINDOW_H
#define MYWINDOW_H

#include <QQuickWindow>

class MyWindow : public QQuickWindow
{
Q_OBJECT

public:
MyWindow(QWindow *pParent = Q_NULLPTR);

protected:
virtual void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
virtual void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
virtual void mouseReleaseEvent(QMouseEvent* e) Q_DECL_OVERRIDE;

private:
bool m_move;
QPoint m_initialMouseClickPos;
};

#endif // MYWINDOW_H


mywindow.cpp

#include "mywindow.h"

#include <QDebug>
#include <QCursor>

MyWindow::MyWindow(QWindow *pParent) :
QQuickWindow(pParent),
m_move(false)
{
setFlags(Qt::FramelessWindowHint);
}

void MyWindow::mouseMoveEvent(QMouseEvent *e)
{
if (m_move) {
const QPoint newMousePosition = e->pos() - m_initialMouseClickPos + position();
setPosition(newMousePosition);
}

QQuickWindow::mouseMoveEvent(e);
}

void MyWindow::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton)
{
m_initialMouseClickPos = e->pos();
m_move = true;
}

QQuickWindow::mousePressEvent(e);
}

void MyWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton)
{
m_move = false;
}

QQuickWindow::mouseReleaseEvent(e);
}

Answer

The problem is that QQuickWindow::mouseXxxEvent() delivers the event to the item it belongs to. You have overridden the event handlers, do your handling first, and then pass on the event to QQuickWindow. Therefore the Slider receives the events right after you have done your custom event handling. Either don't call the base class implementation when you don`t want it to deliver the event to items, or call the base class implementation first and do your custom handling afterwards only if the event was not accepted or so.

void MyWindow::mousePressEvent(QMouseEvent *e)
{
    QQuickWindow::mousePressEvent(e);

    if (!e->isAccepted() && e->button() == Qt::LeftButton)
    {
        m_initialMouseClickPos = e->pos();
        m_move = true;
    }

}