Thanks for pointing this out!

     .import QtQml 2.15 as CoreQML
     console.log(CoreQML.Qt.Checked)

yields:

      At line 2: ReferenceError: CoreQML is not defined

Is that something I should report as a bug? I'd appreciate any other potential 
workarounds.

The .import dance as shown above only works if the JS file is itself imported from a QML file. Otherwise any .import statement simply does nothing. If that's a bug then it has been a bug for a long time. It should probably just be documented to work that way. If you're importing the JS file from a QML file, then most likely QtQml is already in scope, which makes the whole thing pointless.

There are some interesting aspects to the availability and members of the Qt object in Qt5 and Qt6:

With QJSEngine, you generally don't get a Qt object at all. You can trigger the creation of the Qt object by installing QJSEngine::TranslationExtension, though. In Qt5 that gives you an object with pretty much only the "uiLanguage" property. In Qt6 you get a Qt object with all properties and methods, but without the Qt namespace enums.

With QQmlEngine, in Qt5 you always get the complete Qt object, while in Qt6 at first you get the same thing as with QJSEngine and the translation extension. Once the QtQml module is imported, you get the namespace enums, too.

Now, how did this happen?

In Qt5 if we have a QQmlEngine, each and every Qt namespace enum value is added as a property to the Qt object, keyed by a newly created QString, wrapped into a JS string, and the whole thing every time you query one of those enums (until you query something that doesn't exist). You may guess why I've removed this particular piece of code.

In Qt6 once the QtQml module is in scope, the "Qt" name refers to something else: The QtQml module exposes the same Qt object as a singleton also named "Qt", with an extension that is the Qt namespace. Singletons rank above the global object in precedence. That's the secret sauce on how the enums are added.

If you want to work around the problem, there are a number of ways to extend the JavaScript environment. For example:

    QJSEngine engine;
    engine.installExtensions(QJSEngine::AllExtensions);
    engine.globalObject().setProperty(
                QStringLiteral("QtNamespace"),
                engine.newQMetaObject(&Qt::staticMetaObject));
    engine.evaluate(QStringLiteral("console.log(QtNamespace.Checked)"));

You may also want to use QJSEngine::registerModule() if you're working with ECMAScript modules.

Finally, I just came up with this neat trick:

    QJSEngine engine;
    engine.installExtensions(QJSEngine::AllExtensions);
    QJSValue qtObject = engine.globalObject().property("Qt");
    QJSValue qtNamespace = engine.newQMetaObject(&Qt::staticMetaObject);
    qtNamespace.setPrototype(qtObject);
    engine.globalObject().setProperty("Qt", qtNamespace);
    engine.evaluate(QStringLiteral("console.log(Qt.Checked)"));

This pretty much gives you the Qt5 Qt object, probably at a lower cost.

I haven't checked how fast the above is, but it probably doesn't repeatedly create strings for all enum values in the Qt namespace.

Now, it wouldn't be all that hard to do the above prototype trick already when adding the Qt object to the JS global object. I need to check if it opens new compatibility pitfalls, though.

best regards,
Ulf
_______________________________________________
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest

Reply via email to