在VS2012中安装了qt-vs-addin-1.2.1-opensource之后,可以直接新建QT5 Designer Plugin项目来构建插件。但是这里的插件都是基于接口QDesignerCustomWidgetInterface实现的,那我们是否可以自定一个插件接口去实现呢?答案是可以的。下面是实现的效果图,具体实现过程见后文。
一、自定义接口
FilterInterface.cpp
#ifndef FILTERINTERFACE_H
#define FILTERINTERFACE_H
#include <QString>
#include <QImage>
#include <QObject>
class FilterInterface
{
public:
virtual QString name() const=0;
virtual QImage filter(const QImage &image) const=0;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(FilterInterface, "{81AAD42E-1206-443A-8DA2-81C878C23E74}")
QT_END_NAMESPACE
#endif
说明:
1.必须添加QT_BEGIN_NAMESPACE到QT_END_NAMESPACE这一部分,这表明定义了接口。
2.Q_DECLARE_INTERFACE第一个参数是接口的类名,第二个参数是IID。IID在Qt5 Desingner Plugin建立的项目中的QDesignerCustomWidgetInterface所使用的IID是类似于"org.qt-project.Qt.QDesignerCustomWidgetInterface",即在org.qt-project.Qt.后面添加接口的名称,而且在实现接口的类中也采用这样的IID。但是在同一个接口进行多次实现时,如果基于这样的命名方式,有可能导致IID相同,这样在后面动态加载插件时,入口点有可能被认定为是同一个,从而导致两个插件只加载入了一个(我开始时遇到这个问题,折腾了很久才找到这个原因)。后面基于COM组件开发时也有使用IID,而IID是使用GUID的形式生成的,所以我采用了这一形式,将Q_DECLARE_INTERFACE中的IID及后面的IID都使用为GUID。目前正常运行,不知有没有后遗症。
3.将FilterInterface.cpp保存到了Interfaces文件夹下。
二、插件实现
(一)HorizontalPlugin的实现
horizontalplugin.h
#include "../Interfaces/FilterInterface.h"
class FlipHorizontally:public QObject,FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "{6A5B6FCE-94D2-40CB-824C-34EEA2FA7367}" FILE "horizontalplugin.json")
Q_INTERFACES(FilterInterface)
public:
QString name() const;
QImage filter(const QImage &image) const;
};
horizontalplugin.cpp
#include "horizontalplugin.h"
QString FlipHorizontally::name() const
{
return "Horizontally";
}
QImage FlipHorizontally::filter(const QImage &image) const
{
QImage result( image.width(), image.height(), image.format() );
for( int y=0; y<image.height(); ++y )
{
for( int x=0; x<image.width(); ++x )
{
result.setPixel( x, image.height()-1-y, image.pixel( x, y ) );
}
}
return result;
}
说明:
1.需要继承QObject和自定义接口FilterInterface。
2.一般需要使用Q_OBJECT,这样才能使用信号singlas和槽slot.
3.Q_PLUGIN_METADATA是必须的,其中IID使用GUID。FILE中使用的json文件是必要的,默认是只有大括号{}。具体作用尚不清楚,如有路过的大牛,请指点迷津。
4.Q_INTERFACES是必须的,参数是接口名FilterInterface。
5.可以新建Qt5 Designer Plugin项目,然后将头文件和cpp文件都删除,然后引入FilterInterface.h,添加horizontalplugin.h和horizontalplugin.cpp。
6.项目输出目录修改为../Plugins,以便后面调用。
(二)VerticalPlugin的实现
verticalplugin.h
#include "../Interfaces/FilterInterface.h"
class FlipVertically:public QObject,FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "{52D000C5-108A-4A00-B109-8C5509BD8F38}" FILE "verticalplugin.json")
Q_INTERFACES(FilterInterface)
public:
QString name() const;
QImage filter(const QImage &image) const;
};
verticalplugin.cpp
#include "verticalplugin.h"
QString FlipVertically::name() const
{
return "Vertically";
}
QImage FlipVertically::filter(const QImage &image) const
{
QImage result( image.width(), image.height(), image.format() );
for( int y=0; y<image.height(); ++y )
{
for( int x=0; x<image.width(); ++x )
{
result.setPixel(image.width()-1-x,y,image.pixel( x,y));
}
}
return result;
}
说明:参照HorizontalPlugin的说明。
三、动态载入插件
loadplugin.h
#ifndef LOADPLUGIN_H
#define LOADPLUGIN_H
#include <QtWidgets/QMainWindow>
#include <QMap>
#include <QString>
#include <QDir>
#include <QPluginLoader>
#include "../Interfaces/FilterInterface.h"
#include "ui_loadplugin.h"
class LoadPlugin : public QMainWindow
{
Q_OBJECT
public:
LoadPlugin(QWidget *parent = 0);
~LoadPlugin();
private slots:
void filterChanged( QString );
private:
Ui::LoadPluginClass ui;
void findFilters();
QMap<QString, FilterInterface*> filters;
};
#endif // LOADPLUGIN_H
loadplugin.cpp
#include "loadplugin.h"
LoadPlugin::LoadPlugin(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.originalLabel->setPixmap( QPixmap( "../Images/source.png" ) );
connect( ui.filterList, SIGNAL(currentTextChanged(QString)),
this, SLOT(filterChanged(QString)) );
findFilters();
filterChanged( QString() );
}
LoadPlugin::~LoadPlugin()
{
}
void LoadPlugin::findFilters()
{
QDir path( "../plugins" );
foreach( QString filename, path.entryList(QDir::Files) )
{
QPluginLoader loader( path.absoluteFilePath( filename ) );
QObject *couldBeFilter = loader.instance();
if( couldBeFilter )
{
FilterInterface *filter = qobject_cast<FilterInterface*>( couldBeFilter );
if( filter )
{
filters[ filter->name() ] = filter;
ui.filterList->addItem( filter->name() );
}
}
}
}
//
///slots
void LoadPlugin::filterChanged( QString filter )
{
if( filter.isEmpty() )
{
ui.filteredLabel->setPixmap( *(ui.originalLabel->pixmap() ) );
}
else
{
QImage filtered = filters[ filter ]->filter( ui.originalLabel->pixmap()->toImage() );
ui.filteredLabel->setPixmap( QPixmap::fromImage( filtered ) );
}
}
main.cpp
#include "loadplugin.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LoadPlugin w;
w.show();
return a.exec();
}
说明
1.新建Qt5 Application项目,命名为LoadPlugin。
2.在loadplugin.ui添加两个QLabel,分别命名为originalLabel和filteredLabel,再添加一个QListWidget,命名为filterList。
3.使用QDir来加载../Plugins的路径,并用path.entryList来过滤出有入口点的dll,再用QPluginLoader来加载。最后使用qobject_cast<FilterInterface*>来实现强转。
以上就是实现的全过程,具体的源码可以到这里下载http://download.csdn.net/detail/xxdddail/6771015。
转载请注明出处http://blog.csdn.net/xxdddail/article/details/17578191。