原因

最近在用Qt做我的项目,在网上找插件编写的材料,没有残缺的代码,要下载的资源都被传到须要积分的网站上了,感觉很不爽。因而把插件示例我的项目编写残缺,并在github上开了一个qtDemo我的项目,写了这篇文章。
作为一个拖砖我的项目,望大家在学习同时,不要遗记了分享的精力。这个我的项目我会把学习Qt的代码不断更新上来,若有同道者,请pull request给我,本我的项目收集Qt示例程序,谢谢!

技术抉择

我的我的项目最低反对msvc 10.0 x86,g++ 4.8.5,Qt5.5.1,因为须要跨平台,项目管理应用cmake(最低反对3.10),当初同时反对windows和linux,IDE我应用qcreator,在windows下你也能够抉择visual studio 2019。

Cmake介绍

应用cmake次要是因为它的跨平台性好,能够脱离操作系统与IDE的解放,而且曾经被广泛支持了。
设置cmake所需最低版本号

cmake_minimum_required(VERSION 3.10)

我的项目及版本号,项目名称能够通过${PROJECT_NAME}获得

project(plg1 VERSION 0.1.0)

将当前目录退出文件蕴含搜寻目录,若不设置,vs2019与qcreator的当前目录会不兼容。

set(CMAKE_INCLUDE_CURRENT_DIR ON)

关上全局moc与全局uic

set(CMAKE_AUTOMOC ON)set(CMAKE_AUTOUIC ON)

查找零碎中已装置的Qt版本,须要的库。
最好每一个库都要写,Qt也会依据依赖关系主动增加

find_package(Qt5 REQUIRED Widgets)find_package(Qt5Widgets)find_package(Qt5Core)find_package(Qt5Gui)

收集我的们源文件,这有很多办法,大家能够去理解并应用本人喜爱的形式。

FILE(GLOB SRC_FILES "*.cpp" "*.h" "*.ui")

创立工程文件

add_executable(${PROJECT_NAME} ${SRC_FILES})               #可执行文件创立形式add_library(${PROJECT_NAME} SHARED ${HEAD_FILES})      #动态链接库创立形式

增加子项目,也就是咱们的插件

add_subdirectory(sub1)add_subdirectory(sub2)

增加Qt5依赖项

target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Core Qt5::Gui)

Qt5插件

我的项目构造

本示例我的项目包含三个工程,一个主工程,两插件工程。cmake的我的项目是以目录为根底的,每个工程的目录下会有一个cmakelists.txt工程文件。

插件基类

主工程中的plugindemoplugin.h是所有插件的根底,咱们的每个插件都继承自这个类,它做了插件根底申明及咱们的插件能做的行为。本示例每一个插件会给主程序返回一个widget作为centerWidget显示,并提供一个name和information的查问接口,提供插件必要的信息。

class QtPluginDemoInterface{public:    virtual ~QtPluginDemoInterface() {}    virtual QString name() = 0;    virtual QString information() = 0;            virtual QWidget *centerWidget() = 0;  //返回一个Widget设置到centerwidget中进行显示};//s申明接口#define PluginDemoInterface_iid "com.Interface.MainInterface"Q_DECLARE_INTERFACE(QtPluginDemoInterface, PluginDemoInterface_iid)

插件定义

咱们这只对sub1进行一下阐明,sub2是相似的,请自行浏览代码。
子项目的工程文件(cmakelists.txt)与主我的项目的次要的差异是一个是创立可执行文件,一个是创立动态链接库。
头文件plugindemo.h :

#include "../plugindemoplugin.h"class pluginDemo : public QObject, QtPluginDemoInterface{    Q_OBJECT                //Qt类的标识宏,初学Qt的小伙伴要留神,这行是Qt类必须的    Q_INTERFACES(QtPluginDemoInterface)                //这两行申明是插件要求的    Q_PLUGIN_METADATA(IID PluginDemoInterface_iid)public:    pluginDemo(){};    ...        //办法申明,省略};

源文件plugindemo.cpp :

QWidget *pluginDemo::centerWidget(){    auto btn = new QPushButton("One");    //咱们返回一个按钮,作为简略的widget示例    return  btn;}... //其它的省略了,只是固定信息返回

主程序中加载插件

mainwindow.h定义:

QT_BEGIN_NAMESPACEnamespace Ui { class MainWindow; }QT_END_NAMESPACEclass MainWindow : public QMainWindow{    Q_OBJECTpublic:    MainWindow(QWidget *parent = nullptr);    ~MainWindow();    int MainWindow::loadPlugins();    void MainWindow::populateMenus(QObject * pluginInterface,QtPluginDemoInterface*i );    void MainWindow::slt_WidgetActionTriggered();private:    Ui::MainWindow *ui;};

通过loadPlugins函数加载插件:

int MainWindow::loadPlugins(){    QDir pluginsDir = QDir(QCoreApplication::applicationDirPath());  //这里要留神门路须要配置好,把子工程的输入目录配置到主工程    if(!pluginsDir.cd("plugins")) return -1;                                          //下的plugins目录中    foreach (QString fileName, pluginsDir.entryList(QDir::Files))    {        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));        QObject *plugin = pluginLoader.instance();        if(plugin)        {            auto centerInterface = qobject_cast<QtPluginDemoInterface*>(plugin);            if(centerInterface)            {                populateMenus(plugin,centerInterface);  //将插件作为菜单中的一项            }        }    }    return count;}

生成菜单函数:

void MainWindow::populateMenus(QObject * pluginInterface,QtPluginDemoInterface*i ){    static auto menu = menuBar()->addMenu("widgets");  //建设一个菜单项    auto act  = new QAction(i->name(),pluginInterface);    //建设action,获得的插件对象被绑定在其上    connect(act,&QAction::triggered,this,&MainWindow::slt_WidgetActionTriggered);  //事件链接    menu->addAction(act);}

菜单点击事件响应:

void MainWindow::slt_WidgetActionTriggered(){    QtPluginDemoInterface * plg = qobject_cast<QtPluginDemoInterface*>(sender()->parent());    //获得插件对象    auto centerWidget = plg->centerWidget();        //获得插件中返回的widget    //咱们返回的widget其实是QPushButton,用其配置信息为其设置显示内容    (qobject_cast<QPushButton*>(centerWidget))->setText(plg->information());        setCentralWidget(centerWidget);}

我的项目地址

https://github.com/zhoutk/qtDemo

应用办法

git clone https://github.com/zhoutk/qtDemocd qtDemo/plugin & mkdir build & cd buildcmake -A Win32 ..cmake --build .      

小结

抛砖引玉,不吝赐教,谢谢浏览!