QPluginLoader, late binding and signals/slots
-
Hello
I want to use possibilities of late binding using interface classes and QPluginLoader.
With "normal" methods I don't have problems: it is possible to get an instance of my component and to call methods.
The problem is to use SIGNALS and to call connect(), because compiler don't know that MyInterface is an Q_OBJECT.@
class MyInterface
{
public:virtual void Myfunction(int id) = 0;
signals:
void MyIdChanged(int newId);
}
@How to populate signals with help of an interface?
Thanks Thomas
-
Have you already read the "Plugins How-To":http://developer.qt.nokia.com/doc/qt-4.8/plugins-howto.html?
-
The instance of _toolTableEditor could be loaded successfully.
If I like to use to connect to some signals I get the compiler error:3>.\src\NCDPlugin.cpp(183) : error C2664: 'bool QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)': Konvertierung des Parameters 1 von 'ToolEditorInterface *' in 'const QObject *' nicht möglich
@
connect (_toolTableEditor, SIGNAL(toolChangeRequested(ToolItem * )),
this, SLOT(onToolChangeRequested(ToolItem * )));
@It is not clear how to connect to Signals
Thomas
-
Yes they are.
The problem is that _toolTableEditor is declared as:@
ToolEditorInterface *toolTableEditor;
@I use it after loading my plugin:
@
ToolEditorInterface *toolTableEditor = qobject_cast<ToolEditorInterface *> (plugin);
if (toolTableEditor != NULL)
{
// such calls are working
toolTableEditor->Run();
}
@The problem is that compiler doesn't know something about QObject and he doesn't know about inheritance.
-
@class ToolEditorInterface
{
public:
virtual ~ToolEditorInterface(){}
virtual QWidget *getWidget(QWidget *parent = 0)=0;virtual void setActiveToolNumber(int toolNumber)=0;
virtual int getActiveToolNumber()=0;virtual void enableManualToolChange(bool enable)=0;
virtual bool isManualToolChangeEnabled()=0;
virtual void toolChangeRequestFinished(ToolItem *toolItem)=0;
virtual void enableToolMeasurementCycle(bool enable)=0;
virtual bool isToolMeasurementCycleEnabled()=0;
virtual void toolMeasurementCycleFinished(ToolItem *toolItem)=0;virtual void Run()=0;
signals:
void toolChangeRequested(ToolItem * toolItem);
void toolChangeRequestCanceled(ToolItem * toolItem);
void toolMeasurementCycleRequested(ToolItem *toolItem);
void toolMeasurementCycleCancel(ToolItem *toolItem);
};
Q_DECLARE_INTERFACE (ToolEditorInterface, "xxx/1.0");
@ -
But I did what was written in Qt documentation of plugins.
The class which implements the abstract class ToolEditorInterface is surely derived from QObject.
If I now derive additionally from QObject I have 2 times inherited from QObject. In any case I tried it, but compiler gives me other error messages.@
class ToolTableEditorImpl : public QWidget, public ToolEditorInterface
{
Q_OBJECT
Q_INTERFACES(ToolEditorInterface)
public:
ToolTableEditorImpl(QWidget *parent = 0);
~ToolTableEditorImpl(void);QWidget *getWidget(QWidget *parent = 0);
void setActiveToolNumber(int toolNumber);
int getActiveToolNumber();void enableManualToolChange(bool enable);
bool isManualToolChangeEnabled();
void toolChangeRequestFinished(ToolItem *toolItem);void enableToolMeasurementCycle(bool enable);
bool isToolMeasurementCycleEnabled();
void toolMeasurementCycleFinished(ToolItem *toolItem);
void Run();QString _initialDirectory;
QString _initialListPath;
QString _entryForToolList;signals:
void toolChangeRequested(ToolItem * toolItem);
void toolChangeRequestCanceled(ToolItem * toolItem);void toolMeasurementCycleRequested(ToolItem *toolItem);
void toolMeasurementCycleCancel(ToolItem *toolItem);
@ -
Yes, but as you can see it is a QWidget, which should implement ToolEditorInterface.
This automatically has double inheritance of QObject. Additionally I is described, that there is no support of virtual inheritance with QObject.
see Qt Assisatant in "Using the Meta-Object Compiler (moc)".But I think it must be possible to do such things as I planed ...
-
I don't know it's right or not but:
@
#include <QtPlugin>class QWidget;
class IPlugin
{public:
virtual QObject* getObject() = 0; --- see this (like pattern Clone)virtual void someSignal() = 0; virtual void someSlot() = 0; virtual ~IPlugin() {}
};
Q_DECLARE_INTERFACE(IPlugin, "IPlugin/1.0")
@and implementation :
@
class Plugin : public QWidget, public IPlugin {
public:
QObject* getObject() { return this; }
Plugin() {}public slots:
void someSlot() ;signal:
void someSignal() ;
};Q_EXPORT_PLUGIN2(Plugin, Plugin)
@its work for me but i really don't know it's right or not.
-
But did you try to call connect to the signal: someSignal() ?
After receiving the instance of IPlugin as QObject from the QPluginLoader you have to cast it to
IPlugin *. And the compiler will show you a problem also, because IPlugin isn't a QObject.All other things I did in the same manner.
-
You cannot define signals and slots in interfaces, as you would have to subclass QObject, which will result in a non-abstract class. In addition, once your interface dervies from QObject, all classes implementing this interface derive from QObject as well, which means you cannot subclass from other QObject subclasses (like QWidget), as QObject does not support multiple inheritance (this is the problem you are currently running into).
The (or one) solution is to define signals and slots in the interface, but not to subclass QObject. This does not strictily enforce the implementation of those signals and slots in interface implementations at compile time, but it enforces the implementation of the (ordinary) methods and clearly states that they have to be signals and slots in interface implementations. Signals and slots are resolved during runtime and as long as interface implementations subclass any QObject subclass they can be used.
@
class SampleInterface
{
// Delcaring those methods as signals and slots does NOT enforce
// that they are actually implemented as signals and slots in interface
// implentations, but it forces at least an implementation of ordinary
// methods and indicates clearly that those methods should be
// implemented as signals and slots. QMetaObject (or connect()) can
// be used to check if they have been actually implemented as signals
// and slots during runtime.signals:
virtual void sampleSignal() = 0;public slots:
virtual void sampleSlot() = 0;
};
Q_DECLARE_INTERFACE(SampleInterface, "SampleInterface")class SampleQObjectImplementation : public QObject, SampleInterface
{
Q_OBJECT
Q_INTERFACES(SampleInterface)signals:
void sampleSignal();public slots:
void sampleSlot() { qDebug(Q_FUNC_INFO); emit sampleSignal(); }
};
Q_EXPORT_PLUGIN2(sampleQObjectImplementation , SampleQObjectImplementation)class SampleQWidgetImplementation : public QWidget, SampleInterface
{
Q_OBJECT
Q_INTERFACES(SampleInterface)signals:
void sampleSignal();public slots:
void sampleSlot() { qDebug(Q_FUNC_INFO); emit sampleSignal(); }
};
Q_EXPORT_PLUGIN2(sampleQWidgetImplementation , SampleQWidgetImplementation)// Connect to slots and signals using QObject as base class pointer
// (as returned by QPluginLoader::instance())
QObject* sampleQObjectImplementation = new SampleQObjectImplementation;
QObject* sampleQWidgetImplementation = new SampleQWidgetImplementation;QObject::connect(sampleQObjectImplementation, SIGNAL(sampleSignal()),
sampleQWidgetImplementation, SIGNAL(sampleSlot()));// Cast to SampleInterface to call methods directly
SampleInterface sampleInterface = qobject_cast<SampleInterface>(sampleQObjectImplementation);
sampleInterface->sampleSlot();
@
Brain to terminal. Not tested. Exemplary.A variation to this idiom is to add a <code>QObject *object() { return this; }</code> method to the interface, which allows for using signals and slots with an interface pointer as well.
@
SampleInterface sampleQObjectInterface = qobject_cast<SampleInterface>(sampleQObjectImplementation);
SampleInterface sampleQWidgetInterface = qobject_cast<SampleInterface>(sampleQWidgetImplementation);connect(sampleQObjectInterface->object(), SIGNAL(sampleSignal()),
sampleQWidgetInterface->object(), SLOT(sampleSlot()));
@
Brain to terminal. Not tested. Exemplary.