In such case most people, connect to signal from loaded plug-in which is derived from QObject and defined plug-in interface.
Like following sample plug-in,
Plug-in interface.
class Worker { public: virtual ~Worker() {} virtual void doWork() = 0; }; Q_DECLARE_INTERFACE(Worker,"Worker");Plug-in that implements required interface.
class SampleWorker: public QObject,public Worker { Q_OBJECT public: void doWork(); signals: void workDone(); };Plug-in loader code,
QPluginLoader pluginLoader(fileName); QObject *plugin = pluginLoader.instance(); if (plugin) { Worker* worker = qobject_cast<Worker*>(plugin); if (worker) { connect(worker,SIGNAL(workDone()),this,SLOT(workDone())); worker->doWork(); } }In Plug-in loader code, We are creating plug-in object and if plug-in creation is successfully, we are connecting signal workDone() with some slot. Above code will work fine, because SampleWorker has defined workDone signal.
But problem here is, workDone signal is not part of Worker interface, it is defined in implemented plug-in. If plug-in defines required signal than all works well but we are not forcing plug-in to abide with interface.
Proper solution to this problem could be to create plug-in that return Factory, This factory then creates and returns proper object which is derived from Interface or base class that has defined required method and signals.
like shown in my following sample,
class Worker: public QObject { Q_OBJECT public: virtual ~Worker() {} virtual void doWork() = 0; signals: void workDone(); }; class WorkerFactory { public: virtual ~WorkerFactory() {} virtual Worker* newWorker() = 0; }; Q_DECLARE_INTERFACE(WorkerFactory,"WorkerFactory");Here Worker is actual interface that we need, It defines required method and signals so all subclass will have required method and signals.
Sample plug-in implementation.
class SampleWorker: public Worker { Q_OBJECT public: // it emits workDone signal, when its done void doWork(); }; // Plug-in implementation class SampleWorkerFactory: public QObject, public WorkerFactory { Q_OBJECT Q_INTERFACES(WorkerFactory) public: Worker* newWorker() { new SampleWorker(); } };Plug-in loader implementation,
QPluginLoader pluginLoader(fileName); QObject *plugin = pluginLoader.instance(); if (plugin) { WorkerFactory* workerFactory = qobject_castHere plug-in loader code is loading plug-in implementing WorkerFactory interface and asking it to create object that implements Worker interface which define all required method and signals. Now we can connect required signal slots with this worker object.(plugin); if (workerFactory) { Worker* worker = workerFactory->newWorker(); connect(worker,SIGNAL(workDone()),this,SLOT(workDone())); worker->doWork(); } }
A critical bit of information is not mentioned here: in your plugin project file you must include the interface header file in HEADERS. If it is not there, the plugin will fail to load complaining of an undefined symbol which will be the name of a pure virtual function from the interface file.
ReplyDeleteI was having this very problem, and so I created a trivial application and plugin (with factory). Everything worked fine until I added signals to the plugin. A quick Google search for "qt plugin factory interface" took me to this page: http://qt-project.org/forums/viewthread/13950 describing my problem exactly, and providing the solution.
Thank you for the HEADERS tip!
ReplyDelete