Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Plugins and Signal/Slot mechanism
Forum Updated to NodeBB v4.3 + New Features

Plugins and Signal/Slot mechanism

Scheduled Pinned Locked Moved General and Desktop
11 Posts 3 Posters 15.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    julu
    wrote on last edited by
    #1

    Hi.

    I'm currently developing an application with plugins. These plugins should extend the functionality of the MainWinow, such as adding some Buttons in the ToolBar and so on.
    I'd like to connect the Signals/Slots of the plugins to the MainWindow an also among each other.

    Currently I have:

    Interface class:
    @
    class IBasePlugin
    {
    public:
    virtual ~IBasePlugin(){}

    virtual QString name() = 0;
    virtual QString version() = 0;
    

    };

    class IToolbar : public IModule
    {
    public:
    virtual ~IToolbar(){}
    virtual QWidget* getToolbar() = 0;
    virtual QObject* getObject() = 0;
    };
    @

    Implementation of interface:
    @
    class plugin_Toolbar : public QObject, public IToolbar
    {
    Q_OBJECT
    Q_INTERFACES(IToolbar IBasePlugin)

    public:
    plugin_Toolbar();

    QString name()    { return "abc"; }
    QString version() { return "1"; }
    
    QWidget* getToolbar();
    QObject* getObject();
    

    signals:
    void buttonClicked();
    @

    Plugin gets loaded by QPluginLoader and its signal gets connected with:
    @
    connect(toolbar_plugin->getObject(), SIGNAL(buttonClicked()),
    mainWindow, SLOT(close()));
    @

    This works, but doesn't seem to be the best solution.
    I'd like to have signals and slots in my interface, but inheriting QObject in the interface and in the implementation of the interface doesn't work, moc is complaining.
    How can this be achieved, unfortunately this seems to be an infrequent task, haven't found examples.

    Thanks for your help!

    [edit: Last piece of code fixed / Denis Kormalev]

    1 Reply Last reply
    0
    • G Offline
      G Offline
      goetz
      wrote on last edited by
      #2

      I can't see why that's not a good solution?

      If you provide us with your implementation for getToolbar() and getObject() we probably can help further. Do both functions return the same object?

      Also: It is definitely NOT possible to declare signals and slots in an interface, as the inheritance from QObjet is forbidden there.

      If you declare your interfaces with the proper macros you can use qobject_cast and test if a plugin implements a certain interface.

      See the Docs on "qobject_cast":http://doc.qt.nokia.com/4.7/qobject.html#qobject_cast and the "Plug & Paint Example":http://doc.qt.nokia.com/4.7/tools-plugandpaint.html for this.

      http://www.catb.org/~esr/faqs/smart-questions.html

      1 Reply Last reply
      0
      • F Offline
        F Offline
        Franzk
        wrote on last edited by
        #3

        When inheriting from QObject in plugin interfaces, you should have all that in a separate shared lib, so the meta object is properly accessed. Qt Creator is one example of this.

        "Horse sense is the thing a horse has which keeps it from betting on people." -- W.C. Fields

        http://www.catb.org/~esr/faqs/smart-questions.html

        1 Reply Last reply
        0
        • F Offline
          F Offline
          Franzk
          wrote on last edited by
          #4

          Besides that, the plugin will always be seen as or even has to be a QObject, so you can connect to those signals anyway. The only downside is that the signal and slot names aren't clear from the interface...

          "Horse sense is the thing a horse has which keeps it from betting on people." -- W.C. Fields

          http://www.catb.org/~esr/faqs/smart-questions.html

          1 Reply Last reply
          0
          • J Offline
            J Offline
            julu
            wrote on last edited by
            #5

            [quote author="Volker" date="1288282846"]
            If you provide us with your implementation for getToolbar() and getObject() we probably can help further. Do both functions return the same object?
            [/quote]
            No, one returns a member, the other the whole class.
            @
            QWidget* plugin_Toolbar::getToolbar()
            {
            return(m_toolbar);
            }

            QObject* plugin_Toolbar::getObject()
            {
            return(this);
            }
            @

            [quote author="Volker" date="1288282846"]
            Also: It is definitely NOT possible to declare signals and slots in an interface, as the inheritance from QObjet is forbidden there.
            [/quote]
            Allright, I've tried to do this for quite a while, because I thought of having the signals/slots in the interface would be a nice thing. Knowing this prevents me from further failure.
            W/o, the interface isn't fat, so good thing.

            [quote author="Franzk" date="1288329878"]Besides that, the plugin will always be seen as or even has to be a QObject, so you can connect to those signals anyway. The only downside is that the signal and slot names aren't clear from the interface...[/quote]
            Okay, I can live with that.

            Thank you for your help!

            1 Reply Last reply
            0
            • G Offline
              G Offline
              goetz
              wrote on last edited by
              #6

              You can shorten your connect a bit:

              @
              connect(toolbar_plugin, SIGNAL(buttonClicked()),
              mainWindow, SLOT(close()));
              @

              Calling getObject() on plugin_Toolbar is redundant, as both pointers are identical.

              Unfortunately it's not reliable in the client code, that uses the plugin, because the connected signal is not guaranteed to exist in the plugin. You will notice this only at runtime (watch console output for QObjects warnings about failed connections). Alternatively you can use "QMetaObject":http://doc.qt.nokia.com/4.7/qmetaobject.html to look if the object has the wanted signal.

              You can get around this limitation like this:

              Create an abstract base class (like MyAbstractToolbarPlugin), that inherits from OQbject (and probably from non-QObject IBasePlugin), and declare the signal there.

              In your concrete plugin, inherit from MyAbstractToolbarPlugin, then you definitely do have the signal.

              Of course, this solution has another, different downside: You can only implement one QObject base class per plugin.

              http://www.catb.org/~esr/faqs/smart-questions.html

              1 Reply Last reply
              0
              • J Offline
                J Offline
                julu
                wrote on last edited by
                #7

                Allright, I think I've already tried this by doing the following:

                Interface class:
                @
                class IBasePlugin
                {
                public:
                virtual ~IBasePlugin(){}

                virtual QString name() = 0;
                virtual QString version() = 0;
                

                };

                class IToolbar : public IModule, public QObject
                {
                Q_OBJECT
                public:
                virtual ~IToolbar(){}
                virtual QWidget* getToolbar() = 0;
                virtual QObject* getObject() = 0;
                signals:
                void exitClicked();
                };
                @

                And changing the implementation to:
                @
                class plugin_Toolbar : /public QObject,/ public IToolbar
                {
                Q_OBJECT
                Q_INTERFACES(IToolbar IBasePlugin)

                public:
                plugin_Toolbar();

                QString name()    { return "abc"; }
                QString version() { return "1"; }
                
                QWidget* getToolbar();
                QObject* getObject();
                

                signals:
                void buttonClicked();
                @

                But with this I'm getting errors:

                in function ~IToolbar
                undefined reference to vtable for IToolbar

                1 Reply Last reply
                0
                • G Offline
                  G Offline
                  goetz
                  wrote on last edited by
                  #8

                  In your plugin, did you link against the lib/object file of IToolbar?

                  http://www.catb.org/~esr/faqs/smart-questions.html

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    goetz
                    wrote on last edited by
                    #9

                    Ah, and I forgot to mention: You can/should omit IToolbar from the Q_INTERFACES macro, as you directly inherit from it.

                    http://www.catb.org/~esr/faqs/smart-questions.html

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      julu
                      wrote on last edited by
                      #10

                      [quote author="Volker" date="1288343476"]Ah, and I forgot to mention: You can/should omit IToolbar from the Q_INTERFACES macro, as you directly inherit from it.[/quote]
                      Okay, the reason I'm doing this is is to be able to do a qobject_cast to IToolbar. If I use only this macro
                      @
                      Q_INTERFACES(IBasePlugin)
                      @
                      the cast to IToolbar fails.

                      Now I finally got it working, in my Plugins .pro I had to add the header file of the interface(s)
                      @
                      ...
                      HEADERS +=
                      plugin_toolbarright.h
                      ../../interfaces.h #!!! important
                      ...
                      @
                      So thanks @ all, the cryptic undefined references to vtable were quite confusing...

                      Hints for plugin writers:
                      Signals can't be declared virtual, but slots can.

                      1 Reply Last reply
                      0
                      • G Offline
                        G Offline
                        goetz
                        wrote on last edited by
                        #11

                        The qobject_cast to IToolbar should work without listing it in the macro. It's the same as if you inherited from QLabel.

                        But why would you object_cast to IToolbar anyway? That's only needed if you downcast from a QObject pointer to an IToolbar pointer. You can always safely assign a plugin_Toolbar pointer to an IToolbar pointer thanks to inheritance.

                        http://www.catb.org/~esr/faqs/smart-questions.html

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved