How can I connect a "function pointer" to a slot in Qt?
-
Hi there,
I use a C++ sdk from another author. His major function uses a function pointer to give feedback about the progess back to the calling application. This is the only available method.
Pseudocode: hisfunction(string Parameter, FuncPtrInt progress);
How can I connect such a "function pointer" to a slot in Qt?
Thx Alex
-
Hi,
What is the exact signature of the callback ?
What is the signature of the registration function ?Depending on the SDK, you might not be able to register a member function.
-
Hi,
What is the exact signature of the callback ?
What is the signature of the registration function ?Depending on the SDK, you might not be able to register a member function.
@SGaist thx for your reply let me answer:
in MyApp defined globaly: QProgressBar* progress; void MyApp::slotSetProgress(int percent) { //qDebug() << "Progress: " + QString::number(percent); progress->setValue(percent); QApplication::processEvents(); }
In side the SDK header file:
int nChanneltoRGB(string TIFF_path, string RGB_TIFF_path, InkProcess IP, string colorsSpotDefsFile, string writableTempPath, bool labOutput, FuncPtrInt progress);
-
Hi there,
I use a C++ sdk from another author. His major function uses a function pointer to give feedback about the progess back to the calling application. This is the only available method.
Pseudocode: hisfunction(string Parameter, FuncPtrInt progress);
How can I connect such a "function pointer" to a slot in Qt?
Thx Alex
@lacuna Basically, make a free-standing function that matches the library's expectations exactly. Use that as the callback. Then use that callback function as the "adapter" to call the slot you want to have actually do the work with the actual parameters that are convenient in your internal API.
There's no automatic way to connect a completely arbitrary function to a function pointer callback. The callback has to exactly match the expectations of the library that is calling it.
-
@lacuna Basically, make a free-standing function that matches the library's expectations exactly. Use that as the callback. Then use that callback function as the "adapter" to call the slot you want to have actually do the work with the actual parameters that are convenient in your internal API.
There's no automatic way to connect a completely arbitrary function to a function pointer callback. The callback has to exactly match the expectations of the library that is calling it.
Thank you for all your responses. I am still wondering:
From the Qt documentation I found:
https://doc.qt.io/qt-6/signalsandslots.htmlLambda expressions are a convenient way to
pass custom arguments to a slot:connect(action, &QAction::triggered, engine, [=]() { engine->processAction(action->text()); });
How could this look like- if it works - in my case where I have:
In my *.h file:
typedef void (*FuncPtrInt)(int); static void setCallbackFunc(void (*FuncPtrIn)(int percent));
In my *.cpp file:
int nChanneltoRGB(string TIFF_path, string RGB_TIFF_path, InkProcess IP, string colorsSpotDefsFile, string writableTempPath, bool labOutput, (FuncPtrInt) & setCallbackFunc);
-
Thank you for all your responses. I am still wondering:
From the Qt documentation I found:
https://doc.qt.io/qt-6/signalsandslots.htmlLambda expressions are a convenient way to
pass custom arguments to a slot:connect(action, &QAction::triggered, engine, [=]() { engine->processAction(action->text()); });
How could this look like- if it works - in my case where I have:
In my *.h file:
typedef void (*FuncPtrInt)(int); static void setCallbackFunc(void (*FuncPtrIn)(int percent));
In my *.cpp file:
int nChanneltoRGB(string TIFF_path, string RGB_TIFF_path, InkProcess IP, string colorsSpotDefsFile, string writableTempPath, bool labOutput, (FuncPtrInt) & setCallbackFunc);
@lacuna
You would use a lambda to call the static function passing it a parameter, like:connect(signalObject, &SignalObjectClass::signalMethod, [percent]() { callbackFuncPtr(percent); } ); connect(signalObject, &SignalObjectClass::signalMethod, [](int percent) { callbackFuncPtr(percent); } );
The first one passes a variable (e.g. might be a class variable) when it calls
callbackFuncPtr(percent)
, the second one has the signal passpercent
as an argument (emit signalMethod(percent)
). -
@JonB I would expect that the OPs question is meant the other way around: The library expects a callback function and he wants to connect that to a slot.
Unfortunately, the signature of the callback function is not very helpful. Well designed callback functions have an additional parameter
void*
that has to be user provided, like this:typedef void (*FuncPtrInt)(int, void*); int nChanneltoRGB(..., (FuncPtrInt) &setCallbackFunc, void *callbackData);
This allows the user to pass additional data or create a struct that has all the necessary information. The callback function will then always provide this additional data. Your callback could then cast the void pointer back to a pointer of your own data and use it. As this is not the case, you have to work around that.
The only way I can suggest around this problem is to use "global" data. I've put "global" in quotes as this is not the best approach. The most reliable way is to use a function with a static variable like this:
MyClass *getInstance() { static MyClass *myClass = new MyClass(...); return myClass; }
A more general approach would look like this (not sure if this is the prettiest solution):
class CallbackFuncToSignal : public QObject { Q_OBJECT public: static CallbackFuncToSignal &getInstance() { static CallbackFuncToSignal instance; return instance; } static void callbackFunc(int percent) { emit getInstance().callbackCalled(percent); } signals: void callbackCalled(int); };
Now, you can register
CallbackFuncToSignal::callbackFunc
as callback function. The signalcallbackCalled(int)
can then be connected to a slot. The downside is that we have kind of a singleton here and I don't see a way around it. This means that you should make sure the callback is always registered only once. This is a restriction of the library, though. -
@JonB I would expect that the OPs question is meant the other way around: The library expects a callback function and he wants to connect that to a slot.
Unfortunately, the signature of the callback function is not very helpful. Well designed callback functions have an additional parameter
void*
that has to be user provided, like this:typedef void (*FuncPtrInt)(int, void*); int nChanneltoRGB(..., (FuncPtrInt) &setCallbackFunc, void *callbackData);
This allows the user to pass additional data or create a struct that has all the necessary information. The callback function will then always provide this additional data. Your callback could then cast the void pointer back to a pointer of your own data and use it. As this is not the case, you have to work around that.
The only way I can suggest around this problem is to use "global" data. I've put "global" in quotes as this is not the best approach. The most reliable way is to use a function with a static variable like this:
MyClass *getInstance() { static MyClass *myClass = new MyClass(...); return myClass; }
A more general approach would look like this (not sure if this is the prettiest solution):
class CallbackFuncToSignal : public QObject { Q_OBJECT public: static CallbackFuncToSignal &getInstance() { static CallbackFuncToSignal instance; return instance; } static void callbackFunc(int percent) { emit getInstance().callbackCalled(percent); } signals: void callbackCalled(int); };
Now, you can register
CallbackFuncToSignal::callbackFunc
as callback function. The signalcallbackCalled(int)
can then be connected to a slot. The downside is that we have kind of a singleton here and I don't see a way around it. This means that you should make sure the callback is always registered only once. This is a restriction of the library, though.@SimonSchroeder said in How can I connect a "function pointer" to a slot in Qt?:
@JonB I would expect that the OPs question is meant the other way around: The library expects a callback function and he wants to connect that to a slot.
Indeed, but it should be connected to a function which emits a progress signal with the percentage parameter, and that should be connected to a slot.
static void callbackFunc(int percent) { emit getInstance().callbackCalled(percent); }
Exactly that!
-
@SimonSchroeder said in How can I connect a "function pointer" to a slot in Qt?:
@JonB I would expect that the OPs question is meant the other way around: The library expects a callback function and he wants to connect that to a slot.
Indeed, but it should be connected to a function which emits a progress signal with the percentage parameter, and that should be connected to a slot.
static void callbackFunc(int percent) { emit getInstance().callbackCalled(percent); }
Exactly that!
@JonB @SimonSchroeder @wrosecrans @SGaist
Thank you guys for all your help - that looks very promising!
I will let you know the results! Great Help!