C++ Integration with QML, getting SendEvents working after a socket.readready() signal, and processing the data.
-
I am trying to send events from c++ once I have received a UDP Datagram, I have a viewer showing my qml (viewer) that I need to send key press events to after these datagrams are processed.
The problem is that I can not get the send events to send to the viewer. If I send events from the main program it works great, but not from after the ready read signal and reading of datagrams.
I could use a bit of help here, maybe there is a simple fix for this, but it seems silly that you can't send events into the viewer like this.
I have tried: These all are implemented after the signal(ReadyRead()) and processed
QCoreApplication::sendEvent(viewer,KeyPress);
viewer->sendEvent(viewer->rootObject(),KeyPress);
--and many others nothing seems to work.Please Help!
-
Does something in the viewer that should respond have active focus?
-
Yes it has focus, because prior to sendEvent after the datagram, I send several after the viewer is started using a timer object, these work just fine.
-
This works for me, as long as the window has focus from the window manager.
main.cpp
@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QKeyEvent>
#include <QUdpSocket>
#include <QTimer>
#include <QDebug>
#include <QWindow>QQmlApplicationEngine * engine;
class Listener : public QUdpSocket
{
Q_OBJECT
public:
Listener(QObject *parent = 0): QUdpSocket(parent)
{
bind(22222);
connect(this, SIGNAL(readyRead()), this, SLOT(readDatagram()));
}
private slots:
void readDatagram()
{
QUdpSocket::readDatagram(0, 0);
QKeyEvent kp(QEvent::KeyPress, Qt::Key_0, Qt::NoModifier, "0");
QCoreApplication::sendEvent(engine->rootObjects().first(), &kp);
}
};int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);engine = new QQmlApplicationEngine; engine->load(QUrl(QStringLiteral("qrc:///main.qml"))); Listener l; return app.exec();
}
#include "main.moc"
@main.qml
@
import QtQuick 2.2
import QtQuick.Window 2.1Window {
visible: true
width: 360
height: 360TextInput { text: qsTr("Hello World") anchors.centerIn: parent focus: true }
}
@ -
I Tried This and I get: Synbol(s) not Found when trying to build
@#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlApplicationEngine>
#include <QKeyEvent>
#include <QUdpSocket>
#include <QTimer>
#include <QDebug>
#include <QWindow>
#include <QObject>
#include <QUrl>
#include <QString>
#include <QVariant>#include <QQmlContext>
#include <QByteArray>
#include <QHostAddress>
QQmlApplicationEngine * engine;class Listener : public QUdpSocket
{
Q_OBJECT
public:
Listener(QObject parent = 0): QUdpSocket(parent)
{
bind(7755);
qDebug() << "Started Listener";
connect(this, SIGNAL(readyRead()), this, SLOT(readDatagram()));
}
private slots:
void readDatagram()
{
QByteArray datagram;
datagram.resize(QUdpSocket::pendingDatagramSize());
QUdpSocket::readDatagram(datagram.data(), datagram.size());
//processTheDatagram(datagram);
int key = QString::fromUtf8(datagram.data()).toInt();
qDebug() << "Key: " << QString::number(key);
QKeyEvent keyP = new QKeyEvent(QEvent::KeyPress,key,Qt::NoModifier);
QKeyEvent* keyR = new QKeyEvent(QEvent::KeyRelease,key,Qt::NoModifier);
QCoreApplication::sendEvent(engine->rootObjects().first(), keyP);
QCoreApplication::sendEvent(engine->rootObjects().first(), keyR);}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
engine = new QQmlApplicationEngine;engine->load(QUrl(QStringLiteral("qrc:///main.qml"))); Listener l; return app.exec();
}
@
main.qml
@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1ApplicationWindow{
visible: true
width: 1024
height: 768
Rectangle{
id:zzMain
visible: true
width: 1024
height: 768
color: "#56555b"property string source1: "" property string source2 property color bgColor: "#002244" property real volume: 0.25 property string backto: "mainmenu.qml" RowLayout{ id: layout anchors.fill: parent spacing: 6 Item{ id: header1 width: parent.width height: 135 anchors.top: parent.top Loader { id: headerLoader anchors.fill: parent source: "header.qml" } } Item{ anchors.leftMargin: 10 anchors.rightMargin: 10 anchors.topMargin: 10 anchors.left: parent.left anchors.top: header1.bottom width: parent.width height: parent.height - 10 - header1.height Loader { id: sceneLoader focus:true anchors.fill: parent source: "mainmenu.qml" } } Keys.onPressed: { console.log('Key A was pressed'); event.accepted = true } Keys.onReleased: { console.log('Key A was released: ' + event.key); event.accepted = true } } function closeScene() { console.log("[qmlvideo] main.closeScene") console.log("[qmlvideo] main.closeScene->Going to:" + zzMain.backto) sceneLoader.source = zzMain.backto }
}
}
@ -
Please be more specific about which symbols are missing.
It's useful to eliminate anything not related to the problem at hand. For example, the type zzScreen is referenced but not defined. This might mean that it isn't relevant. Leaving it in the example adds noise, without providing the ability to try the code. The content of main.qml likely is relevant, but is missing and as such unusable. Feel free to reference code earlier in the thread instead of retyping if that is the intention.
-
I update the code to inlude everything, and removed the screens element as it was not necessary. You can always substitute another QML for the main menu.qml as it is only a grid item.
-
By any chance are the missing symbols related to Listener?
undefined reference to `vtable for ListenerAt the end of my main.cpp example, there's a #include "main.moc". The code highlighting for #include statements makes it easy to overlook in my opinion. This #include causes qmake to generate a moc rule which will catch the Listener class, despite the lack of a definition of the class in a header file.
I don't see this include statement in the main.cpp you provided. If so, add it and re-run qmake (or cmake, qbs, ...).
Adding that, your code works for me with x86_64 Linux using xcb if the window has focus. I didn't need to implement mainmenu.qml and header.qml.
-
That was it for the building of the project, it builds not, but the qml does not see the keyevents..
-
I should add that I've tried it with 5.3.0 and 5.2.1. What platform are you using? I only have access to Linux with xcb, but maybe someone else knows how to get this to work for your platform.
Are you by any chance switching away to another window to send the UDP packet that triggers the events? If so, that won't work.
It's also worth considering whether key events are the best tool for what you're trying to accomplish. Is a signal, property change, or a direct function call more appropriate? With key events, the application has to deal with changing focus and potential conflicts from a user pressing buttons on a physical keyboard.
-
You were right, and I was being stupid :) I was trying to use the same machine with the remote. i know better than that, but sometimes you just can't see it. Thank you so much!
-
Input handling can be pretty confusing, for developers and users.