Dynamically call methods from a scripting engine using QMetaMethod and QVariant.
-
Hi, I'm wrinting a python api for one of my app using pybind11 (which is the best choice for me, even if it is sometimes not easy to integrate it with some Qt paradigms).
I want to let the programmer using my api to interact with a certain family of qobjects (the editable items) using the meta object system through python.
For the properties it's easy. I just had to wrote a method to convert pybind11::handle to QVariant, treating the cases that matter for my software (strings, numbers and nested editable items) and vice versa.
But for some use cases I need invokable methods (for examples creating a new nested editable item and getting back its attributed id). I found this thread that describe how we can cheat with QGenericReturnArgument, QGenericArgument and QVariant to invoke a method once we know its signature, have the corresponding QVariants converted from the corresponding pybind11::handle (provided in a tuple): Qt invoke method with QVariant.
So I can write something like that:
pybind11::object EditableItemWrapper::invokeMethod(std::string m_name, py::tuple args) { QMetaMethod m = getMeth(m_name); //simplified do_checks(); //see if arguments matches both in numbers and types. int narg = m.parameterCount(); switch(narg) { case 0: //do the business here. void v = NULL; const char* name = QMetaType::type(QMetaType(m.returnType()).metaObject().className()); QVariant retVal (m.returnType(), v); bool sucess = invokeMethod(wrapped_obj(), m_name.c_str(), QGenericReturnArgument(name, retVal.data()); .... case n: //repeat cleverly for each n up to a reasonable maximal under Q_METAMETHOD_INVOKE_MAX_ARGS //use the same tric for input values, creating the appropritate QVariant and giving the data() ptr to QGenericArgument } }
But, the doc says its discouraged to work like that... Why ? (For example there is this limitation on the number of parameters, but it's a needed evil, isn't it ?)
Ideally I'd like to invoke my method given a name, A QVariantList as parameter and get back a QVariant and a status code as return, isn't there something to do it already ?
And is there any other solution ? What do you think ?
Thanks in advance for your answers.
Laurent