简体   繁体   中英

What is the best way to pass a custom class (inherits QObject) to QML?

Having used Qt for C++ applications for quite some time now I wanted to do my next project using QML. I now have the following scenario: 项目架构的伪 UML

  • red : QML files and QML engine
  • blue : C++ classes

Now I want to be able to call C++ functions from my QML files ( green arrows ).

  • Content.qml needs to read properties from WifiManager
  • LiveField.qml and GameField.qml need to show / hide the corresponding C++ views

I used C++ for the views because of some heavy 3D stuff which I'm not that familiar with in QML (I only used QML for the UI menu).

I'd rather not create the C++ classes from within my QML code using qmlRegisterType since I need to do some initializing in my C++ code.

What is the best way to solve my problem?

C++ objects are typically shared using QQmlContext::setContextProperty . You can find more information about QQmlContext here . This makes any object (or value) that you put in the context widely available.

Two words of caution though:

  • Use your context properties only in high-level components, and not in reusable ones, as this will create a direct dependency to these values
  • Be careful to load your GUI after you set all your context properties, to make sure they are accessible by you UI from the start.

C++ side

#include "wifimanager.h"

// That one is required
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlApplicationEngine>   

void main() {
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    WifiManager wifi;
    engine.rootContext().setContextProperty("wifiManager", &wifi);

    engine.load(QUrl("qrc:/main.qml"));
    return app.exec();
}

You can then use wifiManager on the QML side, along with its slots , Q_PROPERTY ies, and signals

Reading a Q_PROPERTY

As with regular QML, you can now bind and read your object's properties.

  • Read: var value = wifiManager.value
  • Bind: someProperty: wifiManager.value

Any QML binding will be re-evaluated automatically whenever the value changes, as long as you emit the associated NOTIFY signal. For example:

Q_PROPERTY(QString ssid READ ssid WRITE setSsid NOTIFY ssidChanged)

Text {
    // Calls the READ getter of your Q_PROPERTY
    // Will automatically update whenever the SSID changes
    text: wifiManager.ssid
}

Writing a Q_PROPERTY

As easy as reading the value, you can write to it by doing wifiManager.ssid = xxx

Button {
    text: "Reset SSID"
    onClicked: {
        // Calls the WRITE setter of your Q_PROPERTY
        wifiManager.ssid = ""
    }
}

Handling signals

Signals can be handled with the Connections object. As with any QML object, you have to prefix your signal's name with on and a capital letter. Which gives onWifiConnected: {} for signal void wifiConnected();

Connections {
    target: wifiManager
    // Handle `wifiConnected` signal
    onWifiConnected: {
        console.log("Connected!")

        // If your `wifiConnected` signal has an argument named `ip`
        // it will be available here under the same name
        console.log("My IP is", ip)
    }
}

Calling slots

Slots and Q_INVOKABLE s are accessible as any other functions in javascript. So you can call wifiManager.disconnect()

Button {
    text: "disconnect"
    onClicked: {
        // Calls the `disconnect` slot or Q_INVOKABLE
        wifiManager.disconnect()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM