QML e UDP Socket



  • Buongiorno a tutti,
    qualcuno ha mai avuto l'esigenza di ricevere (o inviare) pacchetti UDP all'interno di un'applicazione QML/JavaScript in Android?

    Da una prima ricerca fatta (https://forum.qt.io/topic/87143/udp-and-tcp-sockets-with-qml) sembrerebbero esserci due strade: integrazione QML/C++ o Libreria esterna.
    Ho provato a scaricare la libreria ma non sono riuscito a utilizzarla (non ci sono istruzioni). Nei commenti nella pagina GitHub sembrerebbe però che la libreria non funziona su Android (sarà vero...?)

    Per la seconda strada, il link presente nel post (http://doc.qt.io/qt-5/qtqml-cppintegration-topic.html) c'è un esempio di integrazione QML/C++ ma si tratta di un'interazione semplice. In questo caso ci dovrebbe essere, dal lato C++, qualcosa in ascolto continuo sulla porta UDP e, in caso di dato ricevuto, dovrebbe trasferirlo dal lato QML.
    Qualcuno ha mai avuto un'esigenza simile?
    Grazie



  • QML/C++, non usare librerie esterne per una cosa così semplice.
    Io ad esempio ho un'app che in fase di avvio cerca i dispositivi mandando in broadcast un pacchetto udp e poi mostra a video ciò che trova.
    Non pensare sia difficile.

    Ciao ciao.



  • grazie @mrdebug !

    Ho trovato un esempio che allego. In effetti dal lato c++ si apre una porta UDP in ascolto. Alla ricezione di un dato però invia al "lato QML" un evento di tasto premuto (almeno così mi sembra) che viene riconosciuto dall'evento Keys.OnPressed.
    Se invece volessi passare al QML semplicemente i dati ricevuti come dovrebbe essere modificato il codice? oppure chiedo se qualche utente ha un esempio semplice adatto allo scopo.

    (main.cpp)

    #include <QGuiApplication>
    #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(1129);
            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[])
    {
        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.9
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.1
    import QtQuick.Layouts 1.1
    
    ApplicationWindow
    {
        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
                }
            }
        }
    }
    
    


  • Per comunicare cpp verso qml, in cpp devi emettere un evento, ad esempio

    void sendLog(QString Log);
    

    lato qml impllementi la connection, ad esempio

        Connections {
            target: QCMainClass
            onSendLog: sendLog(Log)
        }
    
        ...
    
        function sendLog(Log) {
            console.log(Log)
        }
    


  • Grazie mrdebug,
    sono arrivato ad un risultato.
    Posto il codice a beneficio di tutti gli utenti, anche se c'è un'ultima cosa che non torna.

    1. MAIN.CPP
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    #include "myudp.h"
    
    int main(int argc, char *argv[])
    {
    
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<MyUDP>("MyUDP", 1, 0, "MyUDP");
    
        QQmlApplicationEngine engine;
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    
    }
    
    

    MYUDP.H

    #ifndef MYUDP_H
    #define MYUDP_H
    
    #include <QObject>
    #include <QUdpSocket>
    
    class MyUDP : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QByteArray type READ type WRITE setType NOTIFY typeChanged)
    
    public:
        explicit MyUDP(QObject *parent = 0);
        void SayHello();
    
        QByteArray type();
        void setType(const QByteArray &t);
    
    signals:
        void typeChanged();
    
    public slots:
        void readyRead();
    
    private:
        QUdpSocket *socket;
        QByteArray _type;
    };
    
    #endif // MYUDP_H
    

    MYUDP.C

    #include "myudp.h"
    
    MyUDP::MyUDP(QObject *parent) : QObject(parent)
    {
        socket = new QUdpSocket(this);
        socket->bind(1129, QUdpSocket::ShareAddress);
        connect(socket,SIGNAL(readyRead()),this, SLOT(readyRead()));
    }
    
    // send message in client mode
    void MyUDP::SayHello()
    {
        QByteArray Data;
        Data.append("test message");
        socket->writeDatagram(Data,QHostAddress::LocalHost,5824);
    }
    
    void MyUDP::readyRead()
    {
        QByteArray Buffer;
        Buffer.resize(socket->pendingDatagramSize());;
    
        QHostAddress sender;
        quint16 senderPort;
    
        socket->readDatagram(Buffer.data(),Buffer.size(), &sender, &senderPort);
        qDebug()<< "Message size:" << Buffer.size();
        setType(Buffer);
    }
    
    QByteArray MyUDP::type()
    {
        return _type;
    }
    
    void MyUDP::setType(const QByteArray &t)
    {
        _type = t;
        emit typeChanged();
    }
    
    

    MAIN.QML

    import QtQuick 2.0
    import QtQuick.Controls 2.2
    
    import "main.js" as SpkScript
    import MyUDP 1.0
    
    ApplicationWindow
    {
        id: window
        visible: true
    
        title: qsTr("AESA.Monitor")
        MyUDP
        {
            id:myUdp
            onTypeChanged:
            {
                console.log("[QML]Msg:" + type)
            }
        }
    }
    
    

    L'esempio funziona in ricezione. Il pacchetto ricevuto è contenuto in "type" (lato QML).
    Se si fa una console.log(typeof type) il risultato è "object".

    Se si ricevono caratteri stampabili va tutto bene. Ho provato il codice seguente che trasforma type in stringa permettendo l'uso di tutte le funzioni relative:

        var m=type.toString();
        if(m.slice(0,4)==="col=")
        {
                ecc.ecc...
    

    il problema (nel mio caso) è che ricevo dati binari, per cui la conversione a stringa non funziona più bene (al primo carattere non stampabile la stringa si interrompe).

    Ho provato a ricavare i singoli byte dalla variabile type ma senza successo:
    type[0] ritorna "not defined"
    type.charCodeAt(0) non funziona (non è una stringa)
    ci vorrebbe una conversione ad array ma non so come fare.

    grazie per tutti i suggerimenti
    ciao


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.