如何拦截Qt Quick qml事件?
How to intercept Qt Quick qml events?
我想拦截 Qt Quick 事件,例如 key events, so that I can process them before they reach the current target such as the current focused item,可选择阻止事件在默认事件链中传播。可以通过QML代码处理事件来实现吗?
这可以通过在顶层 window 安装一个 event filter 来实现。
通过保存对 ApplicationWindow
with a QML Singleton (this is not exactly trivial: follow this 或其他指南的引用,并在 ApplicationWindow
的 Component.onCompleted
事件中保存引用,可以在 QML 源代码的任何地方找到和访问顶层 window) .事件过滤器可以使用 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 事件,例如 key events, so that I can process them before they reach the current target such as the current focused item,可选择阻止事件在默认事件链中传播。可以通过QML代码处理事件来实现吗?
这可以通过在顶层 window 安装一个 event filter 来实现。
通过保存对 ApplicationWindow
with a QML Singleton (this is not exactly trivial: follow this 或其他指南的引用,并在 ApplicationWindow
的 Component.onCompleted
事件中保存引用,可以在 QML 源代码的任何地方找到和访问顶层 window) .事件过滤器可以使用 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
}