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



  • Moderator's note:
    Please wrap your code snippets in @-tags or use the code button of the editor. And please open new threads for new questions instead of posting to some unrelated older thread, thanks.



  • 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



  • Are your classes (for the objects _toolTableEditor and this) derived from QObject? They need to be in order to use connect.



  • 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.



  • The ToolEditorInterface must be a subclass of QObject and you must include the interface in the file where you're using the plugin. Otherwise the compiler can't know that the interface is derived from QObject.



  • If the call to @toolTableEditor->Run();@ is compiling, then presumably you are including the appropriate header here. Can we see the definition of the <code>ToolEditorInterface</code> class?



  • @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");
    @



  • Well, there's your problem: <code>class ToolEditorInterface</code> does NOT derive from [[Doc:QObject]], and must.



  • 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);
    @



  • If ToolEditorInterface is already derived from QObject, which it must be to use signals and slots, then there is no need for ToolTableEditorImpl to also derive from QObject: it's already in ToolEditorInterface.



  • 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.



  • Why not just derive ToolEditorInterface from QWidget then, instead of QObject?



  • 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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.