简体   繁体   中英

How to intercept Qt Quick qml events?

I would like to intercept Qt Quick events, such as key events , so that I can process them before they reach the current target such as the current focused item , optionally preventing the event to propagate in the default event chain. Can this be achieved by processing the event in QML code?

This can be achieved by installing a event filter in the top level window. The top level window can be found and accessed everywhere in the QML source by saving a reference to ApplicationWindow with a QML Singleton (this is not exactly trivial: follow this or other guides and save the reference in the Component.onCompleted event of ApplicationWindow ). The event filter can be installed with a C++ QML registered plugin.

The c++ event filter plugin is like this:

#pragma once

#include <QQuickItem>

class QmlEventFilter : public QQuickItem
{
    Q_OBJECT
public:
    Q_PROPERTY(QObject * source READ getSource WRITE setSource)
    Q_PROPERTY(bool filterEnabled READ getFilterEnabled WRITE setFilterEnabled)

public:
    QmlEventFilter()
    {
        m_source = nullptr;
        m_filterEnabled = false;
    }

    ~QmlEventFilter()
    {
        if (m_source != nullptr)
            m_source->removeEventFilter(this);
    }

    void setSource(QObject *source)
    {
        source->installEventFilter(this);
        m_source = source;
    };

    QObject * getSource() { return m_source; }
    void setFilterEnabled(bool value) { m_filterEnabled = value; }
    bool getFilterEnabled() { return m_filterEnabled; }

private:

    void keyPressEvent(QKeyEvent *event) override
    {
        // This is actually called when the QML event handler hasn't accepted the event
        m_qmlAccepted = false;

        // Ensure the event won't be propagated further
        event->setAccepted(true);
    }

    void keyReleaseEvent(QKeyEvent *event) override
    {
        // This is actually called when the QML event handler hasn't accepted the event
        m_qmlAccepted = false;

        // Ensure the event won't be propagated further
        event->setAccepted(true);
    }

    bool eventFilter(QObject *obj, QEvent *event) override
    {
        if (!m_filterEnabled)
            return false;

        bool ret = false;
        switch (event->type())
        {
        case QEvent::KeyPress:
        case QEvent::KeyRelease:
            m_qmlAccepted = true;
            QCoreApplication::sendEvent(this, event);
            ret = m_qmlAccepted;
            break;
        }
        return ret;
    }

private:
    QObject *m_source;
    bool m_filterEnabled;
    bool m_qmlAccepted;
};

It has to be registered before the Qt Quick application like this:

    qmlRegisterType<QmlEventFilter>("MyPlugins", 1, 0, "EventFilter");

Then it can be used in a QML source like this:

import MyPlugins 1.0

[...]

EventFilter
{
    id: filter
    filterEnabled: true // It can also be enabled on demand in other events
    Keys.onPressed:
    {
        // Accepting the event won't propagate the event
        // with the default event chain
        event.accepted = true
        console.log("onPressed")
    }
}

Component.onCompleted:
{
    // Singleton.window is the top level QML ApplicationWindow
    filter.source = Singleton.window
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM