IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

Plugins et signaux


Sujet :

Qt

  1. #1
    Membre averti
    Avatar de Niak74
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    271
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 271
    Points : 333
    Points
    333
    Par défaut Plugins et signaux
    Bonjour,

    Je travaille actuellement sur le développement d'une application et de plugins. Il semble que les connexions Signal/Slot entre plugin et application soient impossible. J'ai parcouru pas mal de forums et tentés pas mal de choses sans succès (cast dynamique, appel implicite, ect...).

    J'ai trouvé une solution qui permet d'obtenir le résultat souhaité (c'est à dire la connexion entre un signal du plugin et un slot de l'application) sans trop de lignes de codes, et sans trop complexifier la chose. Je souhaiterai votre avis sur l'idée, et peut être une alternative à laquelle je ne pense pas...

    Nous avons 3 éléménts : un plugin qui émet des signaux, une application qui charge le plugin et qui contient des slots, et une interface pour le plugin, celle-ci sans signaux (car ne pouvant dériver aussi de QObject). L'idée est d'ajouter une sorte de handler de signal qui sera instancié par l'application, qui possédera l'ensemble des signaux du plugins, et qui se chargera de transmettre les signaux émis par le plugin.

    En pratique, ça donne ceci :

    PluginInterface.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    #include <QWidget>
     
    class PluginInterfaceSignalHandler : public QObject
    {
        Q_OBJECT
     
    public:
        PluginInterfaceSignalHandler(QObject * parent = 0) : QObject(parent){}
     
    signals:
        void pluginSignal();
    };
     
    class PluginInterface
    {
    public:
        virtual void setSignalHandler(PluginInterfaceSignalHandler *) = 0;
        virtual void externalFunction() = 0;
    };
     
    Q_DECLARE_INTERFACE(PluginInterface, "example.project.PluginInterface/1.0")
    Plugin.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <QtGui>
    #include "PluginInterface.h"
     
    class Plugin : public QWidget, PluginInterface
    {
        Q_OBJECT
        Q_INTERFACES(PluginInterface)
     
        //------------------------//
        //-- External functions --//
        //------------------------//
     
    public:
        PluginInterface(QWidget* parent = 0);
     
        void setSignalHandler(PluginInterfaceSignalHandler *);
        void externalFunction();
     
    signals:
        void pluginSignal();
     
        //-----------------------//
        //-- Internal elements --//
        //-----------------------//
    private:
        int privatePluginAttribute;
        void privatePluginFunction();
    };
    Plugin.cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void Plugin::setSignalHandler(PluginInterfaceSignalHandler * handler)
    {
        handler->disconnect();
     
        QObject::connect(this, SIGNAL(pluginSignal()), handler, SIGNAL(pluginSignal()));
    }
    Application.cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    void Application::configurePugin()
    {
        QString pluginsDirPath = "Plugins";
        PluginInterface pluginInterface = 0;
     
        QDir pluginsDir(pluginsDirPath);
        foreach(QString fileName, pluginsDir.entryList(QDir::Files))
        {
            QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
            QObject * plugin = pluginLoader.instance();
            if(plugin)
            {
                pluginInterface = qobject_cast<PluginInterface*>(plugin);
                if(!pluginInterface)
                {
                    qDebug() << "Unable to load Plugin !";
                    return;
                }
            }
        }
     
        //-- Make connections --//
        PluginInterfaceSignalHandler * pluginInterfaceSignalHandler = new PluginInterfaceSignalHandler(this);
        pluginInterface->setSignalHandler(pluginInterfaceSignalHandler);
     
        QObject::connect(pluginInterfaceSignalHandler, SIGNAL(pluginSignal()), this, SLOT(applicationSlot()));
    }
    Un clavier Azerty en vaut deux.

  2. #2
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Personnellement, j'ai fais en sorte que l'interface du plugin soit une simili-factory (ça se prêtait bien à ce que je voulais faire, à toi de voir si c'est bon pour toi).

    Voici la définition des interfaces:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    namespace PhoneSpector
    {
    	/* ScriptInterface allows various script handlers to be developped as plugins.
    	   As an example, look at the rubyhandler project. It handles both .rb and .rbw
    	   scripts, and when started, will run a ruby process while extracting all infos.
    	   The scriptEnded() signal is emitted once all data have been retrieved, or an
    	   error has occured.
    	*/
    	class ScriptInterface : public QObject
    	{
    		Q_OBJECT
     
    	public:
    		ScriptInterface(QObject *parent)
    		:QObject(parent)
    		{
    		}
     
    		virtual ~ScriptInterface() {}
     
    		// Calling this function will launch the given scriptFile
    		virtual void startHandlingScript(const QString& scriptFile, const QString& proxy = QString::null,
    			bool needAuth = false, const QString &username = QString(), const QString &password = QString()) = 0;
     
    		virtual void stopExporter(unsigned int timeout) = 0;
     
    		/* This return all stored results. Obviously, the better moment to call it is when 
    		   you've received the scriptEnded() signal :)
    		   The only reason why it may be empty is when an error has occured. You should
    		   call getError() in turn then.
    		*/
    		virtual const QString& getResults() = 0;
     
    		/* This return all stored error. Obviously, the better moment to call it is when 
    		   you've received the scriptEnded() signal :)
    		*/
    		virtual const QString& getError() = 0;
     
    	signals:
    		// Signal must be emitted as soon 
    		void scriptEnded(bool success);
    	};
     
    	/* ScriptBuilderInterface has the role of an abstract factory.
    	   Each factory is capable of handling a given amount of file extensions, and is able
    	   to create new ScriptInterface descendant instances.
    	   Basically, such a factory is used to be able to create as much ScriptInterface as needed.
    	*/
    	class ScriptBuilderInterface
    	{
    	public:
    		// Calling this method will return a new ScriptInterface-derived instance
    		virtual ScriptInterface* getNewScriptInterface(QObject *parent) = 0;
    		// This return all extensions handled by the script plugin
    		virtual const QStringList& getManagedExtensions() const = 0;
    	};
    }
     
    Q_DECLARE_INTERFACE(PhoneSpector::ScriptBuilderInterface, "PhoneSpector.ScriptBuilderInterface/1.8")
    ScriptBuilderInterface::getNewScriptInterface s'occupe d'instancier une classe dérivant de ScriptInterface propre au plugin en lui passant parent en... parent (what else? )
    Le getManagedExtensions, c'est propre au besoin que j'avais, à savoir quelles extensions de fichiers sont gérées par les plugins.

  3. #3
    Membre averti
    Avatar de Niak74
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    271
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 271
    Points : 333
    Points
    333
    Par défaut
    Tu créés une interface qui contient un pointeur vers un dérivé de QObject, pas bête du tout, merci pour l'info =)
    Un clavier Azerty en vaut deux.

Discussions similaires

  1. Comment lancer Eclipse en incluant ses plugins
    Par eclie dans le forum Eclipse Platform
    Réponses: 8
    Dernier message: 19/02/2009, 08h45
  2. Plugin MySQL
    Par Super Castor dans le forum Eclipse Java
    Réponses: 6
    Dernier message: 30/08/2006, 02h54
  3. [Amstrad] Signaux à gérer port E/S pour lire ROM
    Par Masterglob dans le forum Autres architectures
    Réponses: 7
    Dernier message: 12/01/2005, 12h03
  4. [plugin] XML/XSL
    Par cyrdec dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 29/04/2003, 17h50
  5. plugin winamp
    Par darkfrag dans le forum API, COM et SDKs
    Réponses: 7
    Dernier message: 03/08/2002, 10h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo