在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; };
#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; }
三、动态载入插件
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_Hloadplugin.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 ) ); } }
#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。