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?

isanae
  • 3,253
  • 1
  • 22
  • 47
  • 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. – isanae Oct 01 '16 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. – dtech Oct 01 '16 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. – isanae Oct 01 '16 at 21:56
  • 1
    You will have to do a loooooooot of interfacing... – dtech Oct 01 '16 at 22:53
  • @ddriver I don't understand. They seem to have an awesome infrastructure that makes it very easy to call stuff from javascript, but most of the api isn't actually marked with Q_INVOKABLE. If it were, you'd be able to script _everything_. I'm a bit sad. – isanae Oct 02 '16 at 00:02
  • 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. – dtech Oct 02 '16 at 00:17
  • @ddriver The backend has all been written in C++, I'm just starting on the UI, so it wouldn't be too bad to switch now. I'll have a look at it. Thanks a lot for the advice. – isanae Oct 02 '16 at 01:42
  • You can easily use a `QQmlEngine` and still use widgets, since QML is independent of UI and works with any QObject derived classes. It is even possible to create widget trees in QML, though there is a currently regression (worked in Qt4) that makes a debug build of Qt assert when putting a widget into a non widget parent element in QML – Kevin Krammer Oct 02 '16 at 09:17

1 Answers1

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

Kevin Krammer
  • 5,159
  • 2
  • 9
  • 22
  • 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? – isanae Oct 03 '16 at 18:26
  • 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` – Kevin Krammer Oct 08 '16 at 15:41
  • @KevinKrammer I know it's a long time ago, but would it be possible to post the code? – bibi Aug 05 '20 at 14:58
  • 1
    @bibi Slides and Demo code available from https://www.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 https://www.kdab.com/kdab-qt-world-summit-2019/#qml-scripting – Kevin Krammer Aug 06 '20 at 15:21