PDA

View Full Version : creating QWidget Plugins



Spooky
25th January 2011, 11:11
I want to create QWidget plugins for an application, that implement a certain interface. Those plugins are simply custom views that implement that interface and the main application loads these widgets into the main view.

However, I am not sure how to do this efficiently. I know that the Plugin itself has to be of the form
class MyPlugin : public QObject, public MyPluginInterface
{
Q_OBJECT
Q_INTERFACES( MyPluginInterface )
...
};

I read that, if I want to actually create a QWidget from this plugin, the interface should simply contain
class MyPluginInterface
{
...
QWidget* createWidget(QWidget* parent) = 0;
...
};

And thus there would be another class
class MyWidget : public QWidget
{
...
};

But how would I let the actual Widget itself interact with the application? Wouldn't I need to make a wrapper function in the plugin for every single function of the interface, so that it is passed to the Widget object?

high_flyer
25th January 2011, 11:35
But how would I let the actual Widget itself interact with the application? Wouldn't I need to make a wrapper function in the plugin for every single function of the interface, so that it is passed to the Widget object?
No.


//in your application code
MyWidget *pWidget = m_pPlugin->createWidget();
if(pWidget){
pWidget->someMethod();
}

Spooky
25th January 2011, 11:49
No.


//in your application code
MyWidget *pWidget = m_pPlugin->createWidget();
if(pWidget){
pWidget->someMethod();
}

Well, yeah, I guess it was kind of a stupid question :). I am simply a bit confused on how to implement this the "correct" way. So if I want to create plugins that are independent views in the main application, with which the main application interfaces through a certain interface (i.e. ViewInterface). Would I need to do something like this?


class ViewPlugin : public QObject, public ViewPluginInterface
{
Q_OBJECT
Q_INTERFACES( ViewPluginInterface )
...
};
class ViewPluginInterface
{
ViewWidget* createWidget( QWidget* parent ) = 0;
};
class ViewWidget : public ViewInterface
{
...
};
class ViewInterface : public QWidget
{
...
};

In that case, the createWidget function would be the only function of the plugin interface. And I am not sure the inheritance of QWidget works this way?

high_flyer
25th January 2011, 12:03
In that case, the createWidget function would be the only function of the plugin interface.
The code you post would work, but make little sense as a plugin - since in what way the fact the widget came from a plugin would be different then using new MyWidget() in your application?

It makes sens to use a plugin, when the objects the various plugins provide conform to one interface.
So in your application you don't need to know which class implements the interface, and just use the interface methods - that is the whole idea (very simplified) of using a plugin.
So if you can contain the functionality of all you plugin provided widgets in a fixed set of methods, then you expose those methods through the interface and use an interface pointer to call them, without caring which class currently implemtns it.


class MyPluginInterface
{
MyWidget* createWidget(QWidget* parent) = 0;
void someMethod() = 0;
};



//in your applicaiton
MyWidget *pView = m_pPlugin->createWidget();
if(pView){
pView->someMethod();
}


This brings us back to your previous post.
And yes, you will have to expose all the methods shared by your plugin widgets through the interface.
This is what the interface is for.

Spooky
25th January 2011, 12:17
So if you can contain the functionality of all you plugin provided widgets in a fixed set of methods, then you expose those methods through the interface and use an interface pointer to call them, without caring which class currently implemtns it.Yes, that is the plan at least.





class MyPluginInterface
{
MyWidget* createWidget(QWidget* parent) = 0;
void someMethod() = 0;
};



//in your applicaiton
MyWidget *pView = m_pPlugin->createWidget();
if(pView){
pView->someMethod();
}


This brings us back to your previous post.
And yes, you will have to expose all the methods shared by your plugin widgets through the interface.
This is what the interface is for.Hm, sorry, I don't understand your example :(. In this example, wouldn't the MyPlugin and the MyWidget class have to implement the MyPluginInterface? And wouldn't the implementation of someMethod() be empty in MyPlugin and implemented in MyWidget, while the createWidget() function would be the other way around?

high_flyer
25th January 2011, 13:01
Hm, sorry, I don't understand your example . In this example, wouldn't the MyPlugin and the MyWidget class have to implement the MyPluginInterface?
There is no MyPlugin class.
m_pPlugin in my example is:

MyPluginInterface *m_pPlugin;
And yes, your class needs to implement the interface, since it will derive from it.

you can do the following instead of what you did:


class ViewPluginWidget : public QWidget, public ViewPluginInterface
{
Q_OBJECT
Q_INTERFACES( ViewPluginInterface )
...
};

Spooky
25th January 2011, 13:47
Ok, I think my confusion came from the fact, that I thought the plugin must somehow inherit from QObject and can't be just QWidget only :). However, in that case I don't really need a createWidget function?

I was thinking of doing something like this now:
class ViewPluginInterface : public QWidget // to ensure, that anyone using this interface, is creating it as a QWidget
{
...
};

Q_DECLARE_INTERFACE( ViewPluginInterface, "..." )
class SomeCustomViewPluginForTheApp : public ViewPluginInterface
{
Q_OBJECT
Q_INTERFACES( ViewPluginInterface )
...
};And then at some point in the main application
QDir pluginDir( QApplication::applicationDirPath() );

if ( !pluginDir.cd( "plugins" ) )
return;

foreach( QString fileName, pluginDir.entryList( QDir::Files ) )
{
QPluginLoader loader( pluginDir.absoluteFilePath( fileName ) );
if ( ViewPluginInterface *interface = qobject_cast<ViewPluginInterface*>( loader.instance() ) )
{
// this should be a ViewPluginInterface instance, which in turn is a QWidget instance
...
}
}

high_flyer
25th January 2011, 17:04
Ok, I think my confusion came from the fact, that I thought the plugin must somehow inherit from QObject and can't be just QWidget only
QWidget is a QObject.


class ViewPluginInterface : public QWidget // to ensure, that anyone using this interface, is creating it as a QWidget
{
...
};

You can't do that, since then your interface is not an interface any more.

Spooky
25th January 2011, 17:28
Darn, thx ;). Works now as I intended. However, I made it so that I have a getWidget() function defined in the plugin interface, instead of a createWidget() function, which simply returns this in the implementation of the plugin widget.


class ViewPluginInterface
{
public:
virtual QWidget* getWidget() = 0;
};

Q_DECLARE_INTERFACE( ViewPluginInterface, "..." )
class SomeViewPlugin : public QWidget, public ViewPluginInterface
{
Q_OBJECT
Q_INTERFACES( ViewPluginInterface )

...
QWidget* getWidget();
...
};
...

QWidget* SomeViewPlugin::getWidget()
{
return this;
}

...

Q_EXPORT_PLUGIN2( someviewplugin, SomeViewPlugin )

high_flyer
25th January 2011, 18:08
However, I made it so that I have a getWidget() function defined in the plugin interface, instead of a createWidget() function, which simply returns this in the implementation of the plugin widget.
What for?
You always have an instance of your plugin from the plugin loader...

Spooky
25th January 2011, 18:32
What for?
You always have an instance of your plugin from the plugin loader...Yes, another stupid thing from me ;).

However, the way I implemented it now is still not really the way I want it, because there always only exists one instance of a plugin. There should be multiple instances of these 'views' be available in my application (someone else ran into a similar problem here (http://lists.trolltech.com/qt-interest/2005-12/msg00281.html)). But then I am back to this version (http://www.qtcentre.org/threads/38127-creating-QWidget-Plugins?p=175130#post175130) (more or less), where the plugin interface itself does nothing but specify a factory function for a certain type (e.g. a 'ViewWidget').

high_flyer
25th January 2011, 19:54
There should be multiple instances of these 'views' be available in my application
It looks to me you are confusing things.
And I start to suspect you don't really need a plugin.
Can you explain why it is you are using a plugin and not a normal DLL/shared obj?
You can expose and any nuber of interfaces with your plugin - you only need some sort of function for allocating various types and asking which type your object is, so that you can do the correct conversion on the application side.
So one interface will deal with factoring, the other will describe the various types.
But again the question is WHY do you need it?
Plugins are needed, when you want to be able to extend your application with unknown functionality, that conforms to some rules (interface).
Like new filters to an image editing program for example.
Is this you case?
I suspect not, but I don't know until you explain some more on what it is you are trying to do.

Spooky
25th January 2011, 20:03
It's an application to visualize data. This application will consist of different views to display the data. The application should be able to be extensible with additional views (each view can have multiple instances), that access the same data, via plugins (dlls).

I was simply trying to implement this in a simple way with the QPluginLoader. I thought that this might be a straight forward and easily implementable approach to this problem.

high_flyer
25th January 2011, 20:21
The application should be able to be extensible with additional views (each view can have multiple instances), that access the same data, via plugins (dlls).
That means, you don't need the views supplied from the plugin, but only the extra functionality, exactly as I said in my previous post.
And each plugin will implement one sort of functionality. (for example a filter).
So you don't have to worry about all the stuff you were worrying about.
You application can spawn new views for each found plugin.

Start by implementing one plugin, then you will understand.
Have a look at the examples in the Qt documentation.

Spooky
25th January 2011, 20:56
Hm, well I did look at the examples and I did implement one 'dummy' view as a plugin, via the method I described before. The examples extend, as you said, just certain functionality, but that is not what I need.

The functionality of each view can be very different, just the interface with the main application is always the same. To provide a more specific example, there could be a Scatter Plot view in the application and a Parallel Coordinates view. Both views access the same data, but both views are controlled differently, display different parts of the data and handle the received data differently.

What I want to do is creating plugins that simply implement a certain interface, are loaded into the main application as Widgets and are otherwise independent from each other. The user interface, the visual representation etc. can all be completely different for each view, it's up to the implementation of each individual view.

high_flyer
26th January 2011, 08:58
To provide a more specific example, there could be a Scatter Plot view in the application and a Parallel Coordinates view. Both views access the same data, but both views are controlled differently, display different parts of the data and handle the received data differently.
Then you do the "data crunching" in your plugin, and your application takes the results from the plugin and stores it in a model.
You can then on the applicaiton level spawn as many views as you wish and feed them your model, and you can show in each view any segement of the data in any way you choose, in parallel.
You are over complicating things!