zoukankan      html  css  js  c++  java
  • VS2012基于QT5.1自定接口及插件并实现动态加载

    在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

  • 相关阅读:
    如何使用sendEmail发送邮件
    Linux curl命令详解
    linux比较两个文件是否一样(linux命令md5sum使用方法)
    strace命令用法详解
    strace用法说明
    ORA-12154 TNS无法解析指定的连接标识符
    VNC远程连接阿里云Linux服务器 图形界面
    pycharm配置Git 代码管理
    FireFox浏览器-xpath快速定位插件:Xpath Checker
    odoo 前端模板引擎 Qweb
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7605051.html
Copyright © 2011-2022 走看看