向 QML 应用程序发送键盘事件
Send keyboard event to QML application
我想从线程向我的应用程序发送 Qt::Key_Left 信号。
我尝试使用以下代码发送我的事件,但没有任何反应:
QKeyEvent *event = new QKeyEvent ( QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
QCoreApplication::sendEvent (app, pressEvent);
实际上,这些函数是从侦听端口的线程调用的。问题是否可能是由于这些函数不是从主线程调用引起的?
我只是让你知道我的应用程序是在 QML 中(不知道它是否改变了什么)。我还尝试使用静态函数 QCoreApplication::postEvent
提前谢谢你。
对不起我的英语水平。
No, I didn't and I don't see how to do it. The main thread is busy
with QGuiApplication::exec
主线程并没有真正锁定,在每个事件循环周期之间有一个时间段,它监听来自其他线程的事件。
您可以使用 QMetaObject::invokeMethod()
或通过信号触发插槽,在这两种情况下都使用 Qt::QueuedConnection
,这将使用监听 window 来安排要在关联线程的下一个事件循环周期。
QCoreApplication::postEvent()
应该可以工作,我正在使用它从在 QML 中实现的自定义屏幕控制器发送事件并且它工作正常,但是 QML 确实存在于主线程中,所以大概你的问题是您正在从不同的线程发送。所以我假设如果您安排通过主线程发送的事件,它将按预期工作。
编辑:
好的,我知道出了什么问题,出于某种原因,将事件发布到核心应用程序实例不会将其转发到 qml 引擎和后续的 qml 对象。但是如果接收器设置为根 qml 对象 engine->rootObjects().at(0)
它会工作...有点...
通过 Keys.onPressed
和类似方式接收关注项目的事件,因此,如果这就是您所需要的,那么您已经准备就绪。奇怪的是,如果我使用 TextEdit
之类的东西,这种方法就无法将文本写入字段,尽管模拟使用箭头键移动光标之类的东西确实有效。我什至可以按 shift 修饰符和 select 文本。但是不会写文字...
所以可能并没有想象中那么简单。希望有人能够阐明这个问题。对我来说,这在 Qt 中太典型了,由于一些奇怪的实现细节,非常简单且明显合乎逻辑的事情最终无法按预期工作或根本无法工作。
这是我使用的代码:
class Worker : public QObject {
Q_OBJECT
public slots:
void forwardKeyEvent(int k) {
sendKeyEvent(k);
}
signals:
void sendKeyEvent(int k);
};
class Controller : public QObject {
Q_OBJECT
public:
Controller(QQmlApplicationEngine * e) : engine(e) {
w = new Worker;
t = new QThread;
w->moveToThread(t);
connect(this, SIGNAL(sendKeyEvent(int)), w, SLOT(forwardKeyEvent(int)));
connect(w, SIGNAL(sendKeyEvent(int)), this, SLOT(receiveEvent(int)));
t->start();
}
public slots:
void receiveEvent(int k) {
QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyPress, (Qt::Key)k, Qt::NoModifier));
QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyRelease, (Qt::Key)k, Qt::NoModifier));
}
private:
Worker * w;
QThread * t;
QQmlApplicationEngine * engine;
signals:
void sendKeyEvent(int k);
};
// QML side
Column {
TextEdit {
width: 400
height: 200
Keys.onPressed: console.log("pressed ", event.key)
Keys.onReleased: console.log("released ", event.key)
}
Row {
Repeater {
model: [Qt.Key_Left, Qt.Key_S, Qt.Key_Right]
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
anchors.fill: parent
onClicked: Work.sendKeyEvent(modelData) // this is actually the worker controller
}
}
}
}
}
为了测试线程间事件发布,它做了一些疯狂的来回操作,从 QML 到 C++ 控制器再到另一个线程中的对象,然后返回到控制器然后发布事件。它确实按预期工作 - 来自辅助线程的数据已正确发布到事件循环,但发布的事件未按预期工作。
其实问题出在系统和用户身上,需要关注windows系统才能正常工作。
我想从线程向我的应用程序发送 Qt::Key_Left 信号。
我尝试使用以下代码发送我的事件,但没有任何反应:
QKeyEvent *event = new QKeyEvent ( QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
QCoreApplication::sendEvent (app, pressEvent);
实际上,这些函数是从侦听端口的线程调用的。问题是否可能是由于这些函数不是从主线程调用引起的?
我只是让你知道我的应用程序是在 QML 中(不知道它是否改变了什么)。我还尝试使用静态函数 QCoreApplication::postEvent
提前谢谢你。 对不起我的英语水平。
No, I didn't and I don't see how to do it. The main thread is busy with QGuiApplication::exec
主线程并没有真正锁定,在每个事件循环周期之间有一个时间段,它监听来自其他线程的事件。
您可以使用 QMetaObject::invokeMethod()
或通过信号触发插槽,在这两种情况下都使用 Qt::QueuedConnection
,这将使用监听 window 来安排要在关联线程的下一个事件循环周期。
QCoreApplication::postEvent()
应该可以工作,我正在使用它从在 QML 中实现的自定义屏幕控制器发送事件并且它工作正常,但是 QML 确实存在于主线程中,所以大概你的问题是您正在从不同的线程发送。所以我假设如果您安排通过主线程发送的事件,它将按预期工作。
编辑:
好的,我知道出了什么问题,出于某种原因,将事件发布到核心应用程序实例不会将其转发到 qml 引擎和后续的 qml 对象。但是如果接收器设置为根 qml 对象 engine->rootObjects().at(0)
它会工作...有点...
通过 Keys.onPressed
和类似方式接收关注项目的事件,因此,如果这就是您所需要的,那么您已经准备就绪。奇怪的是,如果我使用 TextEdit
之类的东西,这种方法就无法将文本写入字段,尽管模拟使用箭头键移动光标之类的东西确实有效。我什至可以按 shift 修饰符和 select 文本。但是不会写文字...
所以可能并没有想象中那么简单。希望有人能够阐明这个问题。对我来说,这在 Qt 中太典型了,由于一些奇怪的实现细节,非常简单且明显合乎逻辑的事情最终无法按预期工作或根本无法工作。
这是我使用的代码:
class Worker : public QObject {
Q_OBJECT
public slots:
void forwardKeyEvent(int k) {
sendKeyEvent(k);
}
signals:
void sendKeyEvent(int k);
};
class Controller : public QObject {
Q_OBJECT
public:
Controller(QQmlApplicationEngine * e) : engine(e) {
w = new Worker;
t = new QThread;
w->moveToThread(t);
connect(this, SIGNAL(sendKeyEvent(int)), w, SLOT(forwardKeyEvent(int)));
connect(w, SIGNAL(sendKeyEvent(int)), this, SLOT(receiveEvent(int)));
t->start();
}
public slots:
void receiveEvent(int k) {
QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyPress, (Qt::Key)k, Qt::NoModifier));
QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyRelease, (Qt::Key)k, Qt::NoModifier));
}
private:
Worker * w;
QThread * t;
QQmlApplicationEngine * engine;
signals:
void sendKeyEvent(int k);
};
// QML side
Column {
TextEdit {
width: 400
height: 200
Keys.onPressed: console.log("pressed ", event.key)
Keys.onReleased: console.log("released ", event.key)
}
Row {
Repeater {
model: [Qt.Key_Left, Qt.Key_S, Qt.Key_Right]
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
anchors.fill: parent
onClicked: Work.sendKeyEvent(modelData) // this is actually the worker controller
}
}
}
}
}
为了测试线程间事件发布,它做了一些疯狂的来回操作,从 QML 到 C++ 控制器再到另一个线程中的对象,然后返回到控制器然后发布事件。它确实按预期工作 - 来自辅助线程的数据已正确发布到事件循环,但发布的事件未按预期工作。
其实问题出在系统和用户身上,需要关注windows系统才能正常工作。