Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Objekterstellung C++ Klasse in QML



  • Hallo,

    ich habe mich in den letzten Wochen ein wenig in C++ eingearbeitet und mit den Dokumentationen von QT den Udp Multicast Sender und UdpReceiver nachgebaut. Das ganze hat auch wunterbar funktioniert als QDialog und nach und nach habe die Funktionen erweitert.

    Im nächsten Schritt wollte jetzt jetzt das Projekt auf Qt Quick umsetzen und habe mir ein Fenster gebaut mit einem Button. Ich habe die Klasse für den UdpSender angelegt und die Funktionen die ich per Button aufrufen möchte per Q_INVOKABLE deklariert.

    Als nächsten Schritt habe ich den qmlRegisterType<UdpSender> eingepflegt und diesen in der qml Datei importiert.

    Beim Versuch die Funktion aufzurufen (der AutoComplete bietet mir auch richtig die "UdpSender.sendUdpRequest()" an) bekomme ich die Meldung :

    TypeError: Property 'sendUdpRequest' of object [object Object] is not a function

    Ich nehme an das es vielleicht daher kommt das ich ja kein Objekt der Klasse erstellt habe, aber wo müsste ich das bei einer QtQuick Anwendung machen? Bei den "normalen" QDialog habe ich in der main() das Objekt erstellt und die Funktion aufgetrufen um das Fenster anzuzeigen, bei QTQuick habe ich in der Richtung irgendwie überhaupt nichts gefunden.

    Ich würde mich freuen wenn jemand eine Idee hat.

    Mit freundlichen Grüßen

    Marco



  • Hier die Klasse für den Sender die ich geschrieben hatte um das TestPaket per UDP zu verschicken:

    Die Version ist bis auf die Label, Buttons und QDebug ausgaben gekürzte Version die läuft, "sendRequest()" verschickt per Broadcast im Netzwerk ein QByteArray mit "GetInfo 192.168.100.65 53578", auf das die Gegenseite(n) mit einem QByteArray mit Ihren Verbindungsdaten antworten. Das entgegennehmen der Antwort soll in einer separaten Klasse erfolgen, was bei meinem Widget ein eigenes kleines Programm ist.

    udpsender.h

    #ifndef UDPSENDER_H
    #define UDPSENDER_H
    
    #include <QObject>
    #include <QtNetwork>
    #include <QtCore>
    
    class UdpSender : public QObject
    {
        Q_OBJECT
    public:
        explicit UdpSender(QObject *parent = nullptr);
    
        Q_INVOKABLE void ttlChanged(int newTtl);
        Q_INVOKABLE void sendUdpRequest();
    
    signals:
    
    public slots:
    
    private:
        QUdpSocket udpSocket4;
        QHostAddress groupAddress4;
    };
    
    #endif // UDPSENDER_H
    
    

    und die udpsender.cpp

    #include "udpsender.h"
    
    UdpSender::UdpSender(QObject *parent)
        : QObject(parent),
          groupAddress4(QStringLiteral("239.255.53.59"))
    {
        udpSocket4.bind(QHostAddress(QHostAddress::AnyIPv4), 53578, QUdpSocket::ShareAddress);
    }
    
    void UdpSender::ttlChanged(int newTtl)
    {
        udpSocket4.setSocketOption(QAbstractSocket::MulticastTtlOption, newTtl);
    }
    
    void UdpSender::sendUdpRequest()
    {
        QString ownIP;
        foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
            if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
                 ownIP = address.toString();
        }
    
        QString datastring = "GetInfo 192.168.100.65 53578";
        QByteArray darray = datastring.toUtf8();
    
        udpSocket4.writeDatagram(darray, groupAddress4, 53578);
    }
    
    

  • Moderators

    Morgen,
    wichtiger wäre es die main.cpp zu sehen, dort passiert - im Normalfall - die Magie.

    Prinzipiell gibt es 2 Möglichkeiten cpp Klasse dem QML bereich zur Verfügung zustellen.

    entweder via qmlRegisterType<KlassenName>(const char *ImportName, int versionMajor, int versionMinor, const char *qmlName)

    In einer QML Datei kann man dann diese Klasse importieren import ImportName x.y mit x = Major und y = Minor von zuvor.

    Dann kann man einfach ein ein Object erstellen wie eine ITEM oder Image einfac via

    qmlName {
    id:CppBackend
    ...
    }

    oder

    du erstellst ein Object deiner cpp Klasse in main.cpp und setzt es als globales context property:

    int main(int argc, char *argv[])
    {
        ....
        QQmlApplicationEngine engine;
        MyClass mc;
       engine.rootContext()->setContextProperty("QmlName", &mc);
    }
    

    dann kannst du es einfach überall in deinem QML file via QmlName
    zugreifen.

    Hoffe das hilft.
    Grüße



  • Hallo,

    erstmal vielen Dank für deine Mühe.

    Hier wie gewünscht die main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QtDebug>
    #include "udpsender.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        
        // qmlRegisterType<UdpSender>("de.insynergie.udpsender", 1, 0, "UdpSender");
        
        UdpSender send;
        engine.rootContext()->setContextProperty("UdpSender",&send);
        
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
    
    
        return app.exec();
    }
    

    Auskommentiert ist der Part wie ich es bisher versucht habe per qmlRegisterType.

    Ich habe gerade versucht deinen Tipp über die setContextProperty als globales property umzusetzen. Dabei bekomme ich jetzt die Fehlermeldung: (Unterstrichen wird der '->'

    "member access into incomplete type 'QQmlContext'

    Wenn ich das richtig verstehe muss ich einen Fehler in der udpsender Klasse haben oder?

    Gruß
    Marco


  • Moderators

    @Throndar
    dann fehlt das passende #include:

    #include <QQmlContext>
    


  • Hallo J.Hilk

    du hast mich gerettet! :)

    Ich habe jetzt beide Versionen getestet und beides funktioniert super, ich denke ich werde das Objekt im der QML erstellen um das ggfls. als separates Fenster umsetzen zu können und die Objekte nur bei bedarf zu erzeugen wenn und wo ich sie brauche.

    Vielen vielen Dank,

    Marco


Log in to reply