【问题标题】:How to simulate key pressed event in Qml?如何在 Qml 中模拟按键事件?
【发布时间】:2020-09-14 17:37:26
【问题描述】:

我正在使用 QML 实现自定义虚拟键盘​​。我的目的是在我单击虚拟键盘中的按钮时模拟真实键盘的物理按键信号。我已按照Qt Virtual Keyboard 中的教程进行操作,并成功构建并运行了示例代码。

问题是示例代码在 C++ 类中使用QCoreApplication::sendEvent() 函数将按键事件发送到焦点 QObject。当我在 main.qml 中导入 QtQuick.Controls 1.3 作为指南时效果很好,但是当我更改为 QtQuick.Controls 2.2,这在我的应用程序中是必不可少的。以下是示例代码的核心:

void KeyEmitter::emitKey(Qt::Key key)
{
    QQuickItem* receiver = qobject_cast<QQuickItem*>(QGuiApplication::focusObject());
    if(!receiver) {
        return;
    }
    QKeyEvent pressEvent = QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, QKeySequence(key).toString());
    QKeyEvent releaseEvent = QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
    QCoreApplication::sendEvent(receiver, &pressEvent);
    QCoreApplication::sendEvent(receiver, &releaseEvent);
}

那么如何将按键事件发送到我的应用程序?

【问题讨论】:

  • 请更具体一些。使用 QML Controls 2 是否调用了您的 emitKey 方法?还是sendEvent没有效果?在 emitKey 方法的开头放置一个断点,看看会发生什么。
  • 是的,已经调用了emitKey()方法,但是没有生效

标签: c++ qt qml signals-slots qtvirtualkeyboard


【解决方案1】:

我认为focusObject 是实际点击的按钮,因此发送QKeyEvent 而不是TextField 是没有意义的。

如何传递实际接收器对象的指针,而不是向QGuiApplication 询问focusObject

试试这个:

keyemitter.h 文件(只有头文件,不需要 cpp 文件):

#ifndef KEYEMITTER_H
#define KEYEMITTER_H
#include <QObject>
#include <QCoreApplication>
#include <QKeyEvent>
class KeyEmitter : public QObject
{
    Q_OBJECT
public:
    KeyEmitter(QObject* parent=nullptr) : QObject(parent) {}
    Q_INVOKABLE void keyPressed(QObject* tf, Qt::Key k) {
        QKeyEvent keyPressEvent = QKeyEvent(QEvent::Type::KeyPress, k, Qt::NoModifier, QKeySequence(k).toString());
        QCoreApplication::sendEvent(tf, &keyPressEvent);
    }
};
#endif // KEYEMITTER_H

main.cpp 文件:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include "keyemitter.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView view;
    KeyEmitter keyEmitter;
    view.rootContext()->setContextProperty("keyEmitter", &keyEmitter);
    view.setSource(QStringLiteral("qrc:/main.qml"));
    view.show();
    return app.exec();
}

main.qml 文件:

import QtQuick 2.12
import QtQuick.Controls 2.12
Rectangle {
    anchors.fill: parent
    color: "red"
    Column{
        Row {
            TextField {
                id: tf
                Component.onCompleted: { console.log(tf); }
                text: "123"
            }
        }
        Row {
            Button {
                text: "1"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_1)
            }
            Button {
                text: "2"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_2)
            }
            Button {
                text: "3"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_3)
            }
        }
        Row {
            Button {
                text: "DEL"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_Backspace)
            }
            Button {
                text: "OK"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_Enter)
            }
            Button {
                text: "ESC"
                onClicked: keyEmitter.keyPressed(tf, Qt.Key_Escape)
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    感谢@Ponzifex,

    你是对的。当我单击自定义键盘中的按钮时,焦点对象立即更改为单击的按钮,而不是我想要的文本字段。

    简单地说,将按钮的 focusPolicy 更改为 NoFocus 可以解决我的问题。

    Button {
        id: btnOne                
        focusPolicy: Qt.NoFocus
        text: qsTr("1")
        onClicked: {
            keyEmitter.emitKey( Qt.Key_1 )
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-09-23
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      相关资源
      最近更新 更多