PDA

View Full Version : custom widgets as plugins



cwalsh
22nd February 2006, 15:18
Hi all,

What is the correct strategy for creating a graphical component as a plugin?

For example, if I have an application with two components in the main window, (a browse tree on the left, and a viewing pane on the right), I want to implement each component as a plugin, so that I can drop in new components withou re-compiling my main app.

So I get the view plugin:


ViewInterface *iView = qobject_cast<ViewInterface *>(plugin);

Then get an instance of the view widget:


if (iView){
viewWidget = iView->createWidget(this);
}

where viewWidget is a QWidget*

So now I can insert the plugin into my layout, but I can't access any of the plugins methods because it's now a QWidget, not a Viewer!

I guess this question is more conceptual than technical... any advice?

-Chris

wysota
22nd February 2006, 15:24
Create a common base for all plugins (or separate for each plugin type) and implement such an interface in your plugins. You'll only be able to call methods defined in that base, but that's obvious.

Read the docs and/or search the forum for details. Especially take a look at the "plug and paint" example bundled with Qt.

cwalsh
22nd February 2006, 17:30
Hiya,

I've looked at that example alright, but it doesn't create a gui component, the plugin just provides functionality. What I'm trying to do is load a plugin (or plugins) and insert them into a layout. To do this they will have to be sublassed from a QWidget, but also conform to the plugin interface...

Thanks.
Chris

wysota
22nd February 2006, 17:38
So? What is the problem?

struct WidgetInterface{
virtual QWidget *create(QWidget *parent)=0;
// ...
}
struct ListViewInterface{
virtual QListView *create(QWidget *parent)=0;
// ...
}

Or even use only WidgetInterface and check the widgets classname using Qt's meta data access and cast it to its proper class.

cwalsh
22nd February 2006, 18:43
The problem with this:

struct ListViewInterface{
virtual MyListViewWidget *create(QWidget *parent)=0;
...
};
is that the application has to know what a MyListViewWidget class looks like. Which defeats the purpose of the interface.

What is needed is something like:

struct ListViewInterface{
virtual QWidget *create(QWidget *parent)=0;
...
};
where I could then create a set of plugins:
MyListView
YourListView
AnotherListView
etc...
that all adhere to the ListViewInterface interface.

With the interface defined above, I can call create() and get back a QWidget and then stick that in the layout, but I can't call any of the ListViewInterface defined methods anymore , because i have a QWidget now, not a (QWidget+ListViewInterface)

So, as per your second suggestion, I guess I need to use Qt's meta data access and cast it to its proper class.

Thanks.
-C.

wysota
22nd February 2006, 19:40
But you don't have to return a QWidget from the create method. You can return MyListViewWidget, provided that your main application knows that class.

cwalsh
22nd February 2006, 22:42
I know :) , but as I said in my previous append, this defeats the purpose of the interface, because you have to tell the main the specifics of the class instead of the generics of the interface.

What is needed is a main that uses the interface to communicate with a set of plugins that obey the interface. However the plugins also have to be Widgets so that main can stick them in a layout.

Hmmm... is this possible:


class ListViewInterface : public QWidget
{
virtual MyListViewWidget *create(QWidget *parent)=0;
...
};

????

probably not... must try it... back in a sec!
Chris

wysota
22nd February 2006, 23:02
The interface shouldn't inherit QWidget, because the interface is the interface of your plugin, whereas the plugin (implementing the interface) can create widgets. Now the point is to define base classes for those widgets, so that you can communicate with your plugin-originated widgets without knowing their exact structures. So you can have something like this:


struct MyIFace {
QStringList treeviews()=0;
QStringList simplewidgets()=0;
QStringList buttons()=0;
QStringList gizmos()=0;
QAbstractButton *createButton(const QString &classname, QWidget *p=0)=0;
QWidget *createWidget(const QString &classname, QWidget *p=0)=0;
QTreeView *createTreeView(const QString &classname, QWidget *p=0)=0;
Gizmo *createGizmo(const QString &classname, QWidget *p=0)=0;
};
with Gizmo being your totally custom widget with custom interface.
Members returning string lists let you know, what classes the plugin is able to generate. Knowing that you can call one of "create" methods passing one of the names retrieved earlier and you receive a widget compliant with the given interface. The "Gizmo" thing shows that you're not limited to standard bases, you can have your own ones.