How to expose a normal function to QML?
-
I’m working on a database project written in C that exposes many plain C functions for running queries. We’re now building a QML front end and I want the simplest, lowest-effort way to integrate the two.
I’ve seen forum posts recommending middleware classes that use the
Q_OBJECT
macro andQ_INVOKABLE
methods, registered with the QML engine. Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.) -
I’m working on a database project written in C that exposes many plain C functions for running queries. We’re now building a QML front end and I want the simplest, lowest-effort way to integrate the two.
I’ve seen forum posts recommending middleware classes that use the
Q_OBJECT
macro andQ_INVOKABLE
methods, registered with the QML engine. Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)@Saviz said in How to expose a normal function to QML?:
I’m working on a database project written in C that exposes many plain C functions for running queries. We’re now building a QML front end and I want the simplest, lowest-effort way to integrate the two.
I’ve seen forum posts recommending middleware classes that use the
Q_OBJECT
macro andQ_INVOKABLE
methods, registered with the QML engine. Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)Does the function return a value? A there cleanup function or other funtions that can map to transitions in a UI?
While Q_INVOKABLE almost certainly involves the least code to implement, use usually doesn't fit in with the declarative style of QML. Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
-
@Saviz said in How to expose a normal function to QML?:
I’m working on a database project written in C that exposes many plain C functions for running queries. We’re now building a QML front end and I want the simplest, lowest-effort way to integrate the two.
I’ve seen forum posts recommending middleware classes that use the
Q_OBJECT
macro andQ_INVOKABLE
methods, registered with the QML engine. Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)Does the function return a value? A there cleanup function or other funtions that can map to transitions in a UI?
While Q_INVOKABLE almost certainly involves the least code to implement, use usually doesn't fit in with the declarative style of QML. Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
@jeremy_k said in How to expose a normal function to QML?:
Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
@jeremy_k , please note that @Saviz is dealing with a "plain C" codebase. There are essentially no other options but imperative functions available under that scenario.
I'm subscribed to this question/thread because I am also interested if others have found "the shortest path" (more specifically: the most concise path) to wrapping a free function for QML.
Use of a C++ object will most likely be required (but again: I, too, await any insights from others, since I have not explored this topic in depth).
However, one bit of good news may be the possibility to use a C++ object that does not inherit
QObject
. That could be possible via the "q_gadget" concept: https://doc.qt.io/qt-6/qobject.html#Q_GADGETper the prior link: "
Q_GADGETs
can have Q_ENUM, Q_PROPERTY andQ_INVOKABLE
, but they cannot have signals or slots." -
@jeremy_k said in How to expose a normal function to QML?:
Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
@jeremy_k , please note that @Saviz is dealing with a "plain C" codebase. There are essentially no other options but imperative functions available under that scenario.
I'm subscribed to this question/thread because I am also interested if others have found "the shortest path" (more specifically: the most concise path) to wrapping a free function for QML.
Use of a C++ object will most likely be required (but again: I, too, await any insights from others, since I have not explored this topic in depth).
However, one bit of good news may be the possibility to use a C++ object that does not inherit
QObject
. That could be possible via the "q_gadget" concept: https://doc.qt.io/qt-6/qobject.html#Q_GADGETper the prior link: "
Q_GADGETs
can have Q_ENUM, Q_PROPERTY andQ_INVOKABLE
, but they cannot have signals or slots."@KH-219Design said in How to expose a normal function to QML?:
@jeremy_k said in How to expose a normal function to QML?:
Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
@jeremy_k , please note that @Saviz is dealing with a "plain C" codebase. There are essentially no other options but imperative functions available under that scenario.
As @mzimmers noted, there is no support for Q_INVOKABLE outside of a QObject or Q_GADGET C++ class. I think it's reasonable to presume that OP and the general audience will understand as much at this point in the conversation.
Once we are at that point, it's wise to consider other mechanisms to ease the burden.
-
@jeremy_k said in How to expose a normal function to QML?:
Needing a hundreds of imperative functions sounds like a design in need of better compartmentalization of logic.
@jeremy_k , please note that @Saviz is dealing with a "plain C" codebase. There are essentially no other options but imperative functions available under that scenario.
I'm subscribed to this question/thread because I am also interested if others have found "the shortest path" (more specifically: the most concise path) to wrapping a free function for QML.
Use of a C++ object will most likely be required (but again: I, too, await any insights from others, since I have not explored this topic in depth).
However, one bit of good news may be the possibility to use a C++ object that does not inherit
QObject
. That could be possible via the "q_gadget" concept: https://doc.qt.io/qt-6/qobject.html#Q_GADGETper the prior link: "
Q_GADGETs
can have Q_ENUM, Q_PROPERTY andQ_INVOKABLE
, but they cannot have signals or slots."@KH-219Design Thank you for taking my concern seriously. I’m surprised this topic isn’t covered in more depth.
It feels unreasonable that exposing a simple function to QML requires such a rigid, inconvenient structure. Why does everything need to be a class and include some kind of
Q_OBJECT
/Q_GADET
macro ? If that’s truly the only option, I may have to consider alternatives to QML. It would be simply too much work to create layers just for exposing these functions to the GUI. -
database project written in C that exposes many plain C functions for running queries.
(bold-font emphasis is my own)
Yes. I empathize.
A lot hinges on the magnitude of your "many" quantifier in the original problem description.
I suspect that beyond some threshold it would be reasonable to write an automated wrapper-generator system rather than wrap each C header manually. For loose inspiration on wrapper-generator systems, I'm thinking something like ctypes (C-to-python) or QMetaObject-rs (Rust-to-QML).
Come to think of it, maybe you could use
ctypes
to go from C to Python, then use PySide (Qt Python) for the GUI?** That's still a non-zero amount of work, but I give it pretty favorable odds of being less work than wrapping all your C for Q_GADGET. I guess the trade-off is roughly that you would end up withpy
files as your "glue" between C and QML, instead ofC++
files as your glue between C and QML. Pick your poison? 🧪🧙😈**It isn't incredibly well known, but a GUI in PySide is perfectly able to support QML.
-
@KH-219Design Thank you for taking my concern seriously. I’m surprised this topic isn’t covered in more depth.
It feels unreasonable that exposing a simple function to QML requires such a rigid, inconvenient structure. Why does everything need to be a class and include some kind of
Q_OBJECT
/Q_GADET
macro ? If that’s truly the only option, I may have to consider alternatives to QML. It would be simply too much work to create layers just for exposing these functions to the GUI.@Saviz said in How to expose a normal function to QML?:
It feels unreasonable that exposing a simple function to QML requires such a rigid, inconvenient structure. Why does everything need to be a class and include some kind of
Q_OBJECT
/Q_GADET
macro ? If that’s truly the only option, I may have to consider alternatives to QML. It would be simply too much work to create layers just for exposing these functions to the GUI.That's not an uncommon sentiment among people who are evaluating Qt (and in all candor, is likely one of the reasons Qt doesn't have a broader following). Qt is definitely not a "toe in the water" framework; it's more a "hold your nose and jump in" deal. If your C functions truly measure in the hundreds, you are indeed looking at a big interface layer, though it could probably be handled in a single (large) controller object.
But yeah...Qt might not be the right tool for your application.
-
@KH-219Design Thank you for taking my concern seriously. I’m surprised this topic isn’t covered in more depth.
It feels unreasonable that exposing a simple function to QML requires such a rigid, inconvenient structure. Why does everything need to be a class and include some kind of
Q_OBJECT
/Q_GADET
macro ? If that’s truly the only option, I may have to consider alternatives to QML. It would be simply too much work to create layers just for exposing these functions to the GUI.@Saviz said in How to expose a normal function to QML?:
@KH-219Design Thank you for taking my concern seriously. I’m surprised this topic isn’t covered in more depth.
It feels unreasonable that exposing a simple function to QML requires such a rigid, inconvenient structure. Why does everything need to be a class and include some kind of
Q_OBJECT
/Q_GADET
macro ? If that’s truly the only option, I may have to consider alternatives to QML. It would be simply too much work to create layers just for exposing these functions to the GUI.QML = Qt Meta-object Language.
The meta-object system enables transforming strings in the QML source text into properties (including functions) in a C++ object at runtime. Q_OBJECT and Q_GADGET macros expand into support code, and tell moc to generate corresponding meta-objects.Perhaps you can get what you seek from the javascript engine. I've never felt the need to investigate that route.
-
I’m working on a database project written in C that exposes many plain C functions for running queries. We’re now building a QML front end and I want the simplest, lowest-effort way to integrate the two.
I’ve seen forum posts recommending middleware classes that use the
Q_OBJECT
macro andQ_INVOKABLE
methods, registered with the QML engine. Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)@Saviz said in How to expose a normal function to QML?:
Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)
- As others have pointed out, at least one class with
Q_OBJECT
orQ_GADGET
is required. - You don't need hundreds of classes. You just need one class to hold your many methods/functions (or perhaps a few classes, if you want to organize/group your functions)
- Do you need to expose every single C function directly to your GUI? Perhaps you could design your wrapper class as an abstraction layer that exposes fewer but higher-level methods to QML, while these higher-level functions each call multiple lower-level C functions.
- If you do want to expose hundreds of C functions directly to QML, then it could make sense to write a wrapper script to read your C header and generate the corresponding wrapper C++ method.
- As others have pointed out, at least one class with
-
@Saviz said in How to expose a normal function to QML?:
Before I commit to writing hundreds of thin wrapper classes, is there a way to call plain, non-class member C functions directly from QML? (These functions aren’t attached to any class.)
- As others have pointed out, at least one class with
Q_OBJECT
orQ_GADGET
is required. - You don't need hundreds of classes. You just need one class to hold your many methods/functions (or perhaps a few classes, if you want to organize/group your functions)
- Do you need to expose every single C function directly to your GUI? Perhaps you could design your wrapper class as an abstraction layer that exposes fewer but higher-level methods to QML, while these higher-level functions each call multiple lower-level C functions.
- If you do want to expose hundreds of C functions directly to QML, then it could make sense to write a wrapper script to read your C header and generate the corresponding wrapper C++ method.
@JKSH said in How to expose a normal function to QML?:
Do you need to expose every single C function directly to your GUI? Perhaps you could design your wrapper class as an abstraction layer that exposes fewer but higher-level methods to QML, while these higher-level functions each call multiple lower-level C functions.
You are absolutely right that not all functions need to be exposed to the GUI layer. However, there are still a significant number of functions that do need to be invoked directly from the GUI. For that reason, I believe your proposed solution of creating a controller or wrapper unit with automated C++ generation is indeed the best approach. That said, I’ll continue researching to see if there are any alternative technologies that might be a better fit for my situation.
- As others have pointed out, at least one class with
-
S Saviz marked this topic as a regular topic