PDA

View Full Version : How to create a plugin



MTK358
26th August 2010, 23:16
I created a test application that searches for plugins in a directory, and for every one calls their getWidget() function and adds the widget to a layout.

I have a .h file that contains the plugin interface, including the getWidget() method.

How do I create the plugins (using Qt Creator)? I'm completely clueless.

tbscope
27th August 2010, 06:47
http://doc.qt.nokia.com/4.6/plugins-howto.html

MTK358
27th August 2010, 14:29
Writing a plugin involves these steps:

Declare a plugin class that inherits from QObject and from the interfaces that the plugin wants to provide.
Use the Q_INTERFACES() macro to tell Qt's meta-object system about the interfaces.
Export the plugin using the Q_EXPORT_PLUGIN2() macro.
Build the plugin using a suitable .pro file.

OK, what's a suitable .pro file?

MTK358
27th August 2010, 14:35
I figured it out, but when I compile it says that "myplugin.h:1:17: fatal error: QtGui: No such file or directory".

?????????????????????????

tbscope
27th August 2010, 14:38
Here's a pro file from the examples:


TEMPLATE = lib
CONFIG += plugin static
INCLUDEPATH += ../..
HEADERS = basictoolsplugin.h
SOURCES = basictoolsplugin.cpp
TARGET = $$qtLibraryTarget(pnp_basictools)
DESTDIR = ../../plugandpaint/plugins

# install
target.path = $$[QT_INSTALL_EXAMPLES]/tools/plugandpaint/plugins
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS basictools.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/tools/plugandpaintplugins/basictools
INSTALLS += target sources

The file is explained at the end of this webpage:
http://doc.qt.nokia.com/4.6/tools-plugandpaintplugins-basictools.html

tbscope
27th August 2010, 14:39
I figured it out, but when I compile it says that "myplugin.h:1:17: fatal error: QtGui: No such file or directory".

?????????????????????????

Did you use "INCLUDEPATH +=" (note the +) in your pro file?

MTK358
27th August 2010, 14:40
static? I thought it had to be dynamic!

MTK358
27th August 2010, 14:40
INCLUDEPATH += what?

tbscope
27th August 2010, 14:46
Plugins do not have to be dynamic. Usually, plugins are a special kind of library, not used in other programs.
But, if you have the need to base other plugins on a certain base plugin, than you find it much easier when they are shared instead of static. Well, that's what I think.

Forget about the includepath. I thought you might have added such a line in your .pro file. And if you do not add the +, it will overwrite all the include paths resulting in some includes not being found.
But I guess in your case the problem is somewhere else.

Can you post the code you have please?

MTK358
27th August 2010, 14:48
myplugin.h

#include <QLabel>

#include "/home/michael/Projects/QPanel/qpanelappletinterface.h"

class ClockPlugin : public QObject, public QPanelAppletInterface
{
Q_OBJECT
Q_INTERFACES(QPanelAppletInterface)

public:
MyPlugin();
QWidget* getWidget();
void showPreferencesDialog();

private:
QLabel* label;
};



myplugin.cpp

#include "myplugin.h"

MyPlugin::MyPlugin()
{
label = new QLabel("Time goes here");
}

QWidget* MyPlugin::getWidget()
{
return label;
}

void MyPlugin::showPreferencesDialog()
{
// no preferences
}



myplugin.pro

################################################## ####################
# Automatically generated by qmake (2.01a) Fri Aug 27 08:29:32 2010
################################################## ####################

TEMPLATE = lib
CONFIG = plugin
TARGET =
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += myplugin.h
SOURCES += myplugin.cpp

tbscope
27th August 2010, 14:59
I'm not sure about the QtGui error at the moment.

Check the source code, your class is called ClockPlugin while everywhere else it is called MyPlugin.

You also need to set a target.
And you need to call that target in the Q_EXPORT_PLUGIN2 macro. Otherwise you're not exporting symbols and the plugin will not be able to be loaded.

Example:
myplugin.pro:

TARGET = $$qtLibraryTarget(mysuperplugin)

myplugin.cpp: (at the very end of the file)

Q_EXPORT_PLUGIN2(mysuperplugin, MyPlugin)

MTK358
27th August 2010, 15:26
What is "mysuperplugin"?

tbscope
27th August 2010, 15:30
It's the library name of the plugin. You can call it whatever you want.

MTK358
27th August 2010, 15:55
OK, but what about the fact that QtGui is not found?

tbscope
27th August 2010, 16:01
Ohh yes, now I see it.

Add QT += gui to your pro file.

Edit: On the other hand, this should be default, at least for the app template.

MTK358
27th August 2010, 16:04
Didn't help.

tbscope
27th August 2010, 16:11
This is weird. I don't see the problem. QMake should find it automatically.

MTK358
27th August 2010, 16:16
$ ls
Makefile myplugin.cpp myplugin.h myplugin.pro
$ cat myplugin.pro
################################################## ####################
# Automatically generated by qmake (2.01a) Fri Aug 27 08:29:32 2010
################################################## ####################

QT += gui
TEMPLATE = lib
CONFIG = plugin
TARGET = $$qtLibraryTarget(myplugin)
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += myplugin.h
SOURCES += myplugin.cpp
$ qmake
$ make
g++ -c -m64 -pipe -march=x86-64 -mtune=generic -O2 -pipe -fPIC -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I. -o myplugin.o myplugin.cpp
In file included from myplugin.cpp:1:0:
myplugin.h:1:17: fatal error: QtGui: No such file or directory
compilation terminated.
make: *** [myplugin.o] Error 1

tbscope
27th August 2010, 16:25
As you can see in the following line:


g++ -c -m64 -pipe -march=x86-64 -mtune=generic -O2 -pipe -fPIC -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I. -o myplugin.o myplugin.cpp

The following include paths are at least missing:


-I/usr/include/.../QtCore -I/usr/include/.../QtGui
These are pseudo paths, I don't know where they are on your system.

This is mighty strange as, like I said, when QT += gui and QT += core (which are default, you don't generally have to add those manually to the .pro file) are added to your .pro file, the include paths should be set by qmake.

One thing I can think of is to manually delete the Makefile, and try qmake and make again. But I guess this won't solve it either.

Edit: try this too:


CONFIG += plugin
Note the +
When you do not add the +, you erase all the configs

MTK358
27th August 2010, 16:38
Another error:

$ make
/usr/bin/qmake -unix -o Makefile myplugin.pro
g++ -c -m64 -pipe -march=x86-64 -mtune=generic -O2 -pipe -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_PLUGIN -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -I. -o myplugin.o myplugin.cpp
myplugin.cpp: In function ‘QObject* qt_plugin_instance()’:
myplugin.cpp:18:1: error: cannot allocate an object of abstract type ‘MyPlugin’
myplugin.h:6:1: note: because the following virtual functions are pure within ‘MyPlugin’:
/home/michael/junk/QPanel/qpanelappletinterface.h:13:18: note: virtual void QPanelAppletInterface::showSettingsDialog()
make: *** [myplugin.o] Error 1


The interface:

#ifndef QPANELAPPLETINTERFACE_H
#define QPANELAPPLETINTERFACE_H

#include <QtPlugin>

class QPanelAppletInterface
{
public:
virtual ~QPanelAppletInterface() {}

virtual QWidget *getWidget() = 0;

virtual void showSettingsDialog() = 0;
};

Q_DECLARE_INTERFACE(QPanelAppletInterface, "com.trolltech.PlugAndPaint.QPanelAppletInterface/1.0")

#endif // QPANELAPPLETINTERFACE_H

tbscope
27th August 2010, 16:48
Yes, you need to add the void showSettingsDialog() function to MyPlugin

MTK358
27th August 2010, 16:57
My main application now "unexpectedly finishes" if I uncomment the commented out line:


dirIter.next();
QPluginLoader loader(dirIter.filePath());
QPanelAppletInterface *plugin = qobject_cast<QPanelAppletInterface*>(loader.instance());
//ui->appletLayout->addWidget(plugin->getWidget());

tbscope
27th August 2010, 17:03
Most probably, plugin is 0 resulting in the crash.

To prevent the crash, but not solve it do this:

if (plugin)
ui->appletLayout->addWidget(plugin->getWidget());

Now, to solve the plugin problem.
1. check if loader does point to the correct file. This means that dirIter.filePath() should be the same as "/home/you/where/the/plugin/is/myplugin.so"
2. Check if the cast can actually be performed. Therefor, the instance returned by the plugin loader needs to be correct at least.

MTK358
27th August 2010, 17:20
It finally works!!!

The problem is that it was trying to load the files "." and "..".

tbscope
27th August 2010, 17:22
Nice, well done.