0

I'm using a QJSEngine to make an application scriptable. I'd like the JavaScript side to be able to modify the user interface. My main issue right now is accessing the Qt API from JavaScript.

To create widgets, I added a createWidget() wrapper that uses QUILoader:

// JavaScript
var w = helpers.createWidget("QPushButton");

// C++
QJSValue helpers::createWidget(QString type)
{
    QUILoader ld;
    return engine.newQObject(ld.createWidget(type));
}

I've also registered all the enums from qt_getQtMetaObject(), which seems to take care of all the namespace-level enums from qnamespace.h. It doesn't look like it's part of the public API though.

Am I really supposed to this stuff manually or am I missing something? Isn't there a registerAllTheThings() function that creates a global Qt object through which the Qt API available?

If there isn't, then I have a problem. I can create QWidgets with a QUILoader, but I couldn't find a way of creating other objects, such as a QStandardItemModel. I thought all Qt classes would already be registered through qRegisterMetaType(), but they're not: QMetaType::type("QStandardItemModel") fails by returning UnknownType. Again, am I missing some initialization function call that registers everything?

8
  • Okay, none of the member functions in QStandardItemModel or QStandardItem are marked as Q_INVOKABLE, so I can't even call them. I might just have overestimated the scripting abilities of Qt. Commented Oct 1, 2016 at 18:04
  • 1
    If you want a scriptable application, then use QML instead of QtWidgets. Then you can use JS natively with your entire API. You can get away with using very little C++ code in the core. Doing it with QtWidgets is utterly obtrusive. Doing it in QML is easy peasy. QML is "compiled" on the go, so using code generation you can create entirely new types during the runtime. Commented Oct 1, 2016 at 21:52
  • @ddriver This is actually what I've been working on for the past 4 hours, but this is only for extensions. The main application is in C++. I'm currently trying to load QML files at runtime, but I'm not sure how they'll interact with the QtWidgets stuff yet. Commented Oct 1, 2016 at 21:56
  • 1
    You will have to do a loooooooot of interfacing... Commented Oct 1, 2016 at 22:53
  • 1
    Well, those C++ Qt classes long predate QML, so it shouldn't surprise that they aren't designed to be used from QML. Plus I already said, that's quite the bad idea. If your application is not too big, it will be easier to port it to QML. Commented Oct 2, 2016 at 0:17

1 Answer 1

1

I would recommend using a QQmlEngine instead of the QJSEngine.

Is is derived from QJSEngine so it can do the same things, in the same module so no extra dependencies.

It provides an easy way to register types for instantiation in QML, has a plugin loading mechanism (imports), etc.

I presented that as part of my talk at Qt World Summit 2015: https://www.youtube.com/watch?v=7LsKoVrb8C8

Sign up to request clarification or add additional context in comments.

4 Comments

After playing with this for a few hours, my understanding is that QML is a hybrid that requires C++ for certain tasks, such as the model for a TreeView. This doesn't seem very suited to writing extensions. Am I correct?
Basically all types that are not part of the JavaScript language are, at some point, backed by C++ code. Even the types of JavaScript itself might directly translate to C++ types but that is hidden inside the engine. When using QML for UIs, e.g. with QtQuick, BB10 Cascades or DeclarativeWidgets, then models are often implemented directly in C++. But one can also create base types that can then be extended and/or populated on the script side, e.g. QtQml.Model's ListModel
@KevinKrammer I know it's a long time ago, but would it be possible to post the code?
@bibi Slides and Demo code available from kdab.com/development-resources/kdab-qt-world-summit-2015 Just scroll down to the entry for my talk I also had a follow-up talk at Qt World Summit 2019 kdab.com/kdab-qt-world-summit-2019/#qml-scripting

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.