共计 3846 个字符,预计需要花费 10 分钟才能阅读完成。
原因
最近在用 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_NAMESPACE | |
namespace Ui {class MainWindow;} | |
QT_END_NAMESPACE | |
class MainWindow : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
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/qtDemo | |
cd qtDemo/plugin & mkdir build & cd build | |
cmake -A Win32 .. | |
cmake --build . |
小结
抛砖引玉,不吝赐教,谢谢浏览!