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