如何拦截 Qt Quick qml 事件?

Posted

技术标签:

【中文标题】如何拦截 Qt Quick qml 事件?【英文标题】:How to intercept Qt Quick qml events? 【发布时间】:2017-06-17 13:33:47 【问题描述】:

我想拦截 Qt Quick 事件,例如 key events,以便我可以在它们到达当前目标(例如当前 focused item)之前对其进行处理,可选择阻止事件在默认事件链中传播。这可以通过在QML代码中处理事件来实现吗?

【问题讨论】:

【参考方案1】:

这可以通过在顶层窗口中安装event filter 来实现。 通过使用 QML Singleton 保存对 ApplicationWindow 的引用,可以在 QML 源代码中的任何地方找到和访问***窗口(这并非微不足道:遵循 this 或其他指南并将引用保存在 Component.onCompleted 事件中ApplicationWindow)。事件过滤器可以通过 C++ QML 注册插件安装。

c++事件过滤插件是这样的:

#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;
;

它必须像这样在 Qt Quick 应用程序之前注册:

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

然后它可以像这样在 QML 源中使用:

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

【讨论】:

以上是关于如何拦截 Qt Quick qml 事件?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Qt Quick (QML) ListView 项目无法选择?

Qt Quick - 如何仅通过 c++ 代码与 qml 属性交互

qt-quick(qml) 应用程序无法订阅 ros 主题

Qt 创建一个对触摸事件敏感的 QML 滑块

Qt5 和 QML:如何使用 WebEngine Quick Nano Browser 自动输入用户名和密码

如何在 Qt Quick 中将 QML 项目转换为相应的 C++ 项目