see also: animation while waiting

2021-03-09

New: fast, convenient JS calls

JS interpreter versus direct JS calls

If you ever tried to draw something on a QML canvas, you probably know the problem: we certainly don't want to draw directly in JS, but we absolutely need a minimum number of trivial JS glue code functions, to be called from the Lisp side.

We already have the Lisp function qml:js, constructing a string and feeding it to the JS interpreter. The advantage of this approach is that we can eval arbitrary JS code, including variables or properties present in QML. For calling a JS function, we need to write:


 ;; conversion to string needed
 ;; (note: 'js-arg' is now obsolete)
 (js *canvas* "lineTo(~D, ~D)" x y)
      

But the above function is less than suboptimal for repeated calls of JS functions, especially if we need to pass float values, or (nested) Lisp lists.

Of course this wouldn't be Qt5/ECL if there were no way to optimize it. So, looking at some example how to make fast JS calls from C++, I added a new, low-level way of direct JS calls. Here is what you can do now, using qml:qjs:


 (qjs |drawLine| *canvas* 0 0 500.0 0)

 (qjs |addItems| *model* (list (list "Frank" 42)
                               (list "Susan" 40)))
      

The above calls are both fast and direct, and don't need ugly conversions to strings and don't need to call the JS interpreter. The second example, passing a nested Lisp list, will be seen in JS/QML as a nested array, which can be conveniently processed by a trivial JS/QML glue code function to populate an item model.

You can pass up to 10 arguments. The supported argument types include:

t nil integer float string list

So, this new method of calling JS functions is very fast, conses very little, and is also very convenient for passing (nested) Lisp lists. It's implemented at the lowest level possible, using an ECL function defined in C++ and some low level Qt code (see src/ecl_fun.cpp::qjs_call in EQL5 sources).


Conclusion

If you want to either draw something more complex on a QML Canvas (many function calls), or need to pass big amounts of data or nested lists to QML (for populating a model), there is now a fast and convenient way to do it!