Qt插件开发_入门教程

文章目录

  • 前言
  • 插件的好处
  • 具体流程
    • 1. 第一,我们先创建一个主框架应用(**第一个工程**)
    • 2. GUI 设计 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f215270ccfac4e038e7261c4b4891ec1.png)
    • 3. 创建动态库项目(**第2个工程**)
    • 4. 给插件项目添加qt界面类
    • 5.在插件工程添加一个头文件
    • 6. 编辑上面新建的头文件
    • 7.编辑插件工程的头文件和cpp文件
    • 8.去掉插件工程的影子编译
    • 9.找到插件的文件路径
    • 10.将PluginInterface.h添加到主框架中
    • 11.把插件工程的dll文件也拷贝到主框架工程中![在这里插入图片描述](https://img-blog.csdnimg.cn/61bea6b54d2848a3a40a08887d3c8b6c.png)
    • 12. 打开主框架界面头文件
    • 13.mainwindow.cpp
  • 补充:这个博主我真的栓q,很多细节没有讲
    • 1. error: Undefined interface=>这个非常重要,在沟通插件工程与主框架工程的这个头文件中,必须加上这个!!!
    • 2. error: C2039: "qt_metacall"
    • 3.error: C2039: "staticMetaObject": 不是 "PluginInterface" 的成员
    • 4.error: C2338: qobject_cast requires the type to have a Q_OBJECT macro
    • 5.error: C2440: “static_cast”: 无法从“QObject *”转换为“T”
  • 效果
    • 运行
    • 点击
    • 代码结构
  • 代码地址
  • 教程

前言

qt插件我虽然没用过,但是最近看了很多有关三维软件的开发,都是用qt做的,其中就用到了qt插件开发,今天来圆一下梦 : 终于有时间来填一下这方面知识的坑了!

插件的好处

    1. 减少主程序体积和占用内存大小
    1. 按模块升级不会影响到其他
    1. 效率高和维护成本低

具体流程

我们需要创建两个工程

1. 第一,我们先创建一个主框架应用(第一个工程)

2. GUI 设计 在这里插入图片描述

3. 创建动态库项目(第2个工程)

文件->New Project->
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 给插件项目添加qt界面类

在这里插入图片描述
在这里插入图片描述
加一个label:
在这里插入图片描述

5.在插件工程添加一个头文件

在这里插入图片描述
在这里插入图片描述

6. 编辑上面新建的头文件

在这里插入图片描述

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QWidget>

#define PluginInterfaceIID "com.szweebon.PluginInterface/1.0.0"
class PluginInterface{
public:
    virtual ~PluginInterface() = default;
    virtual QWidget *getWidget() = 0;
};

#endif // PLUGININTERFACE_H

7.编辑插件工程的头文件和cpp文件

在这里插入图片描述

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QWidget>

#define PluginInterfaceIID "com.szweebon.PluginInterface/1.0.0"


class PluginInterface{
public:
    virtual ~PluginInterface() = default;
    virtual QWidget *getWidget() = 0;
};

Q_DECLARE_INTERFACE(PluginInterface,PluginInterfaceIID)//此宏必须定义,否则外部程序会报错。

#endif // PLUGININTERFACE_H

在这里插入图片描述

#include "plugindemo.h"
#include "form.h"

PluginDemo::PluginDemo()
{
    mGenWidget = Q_NULLPTR;
}

PluginDemo::~PluginDemo()
{
    if(mGenWidget){
        mGenWidget->deleteLater();
    }
}

QWidget *PluginDemo::getWidget()
{
    if(!mGenWidget){
        mGenWidget = new Form;
    }
    return mGenWidget;
}

8.去掉插件工程的影子编译

在这里插入图片描述
在这里插入图片描述

9.找到插件的文件路径

在这里插入图片描述
在这里插入图片描述

10.将PluginInterface.h添加到主框架中

在这里插入图片描述

11.把插件工程的dll文件也拷贝到主框架工程中在这里插入图片描述

我发现主框架目录有两个位置都有可执行目录,
我直接两个全放了,如下:
在这里插入图片描述
在这里插入图片描述

12. 打开主框架界面头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPluginLoader>//插件加载类

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    QPluginLoader  loader;
};
#endif // MAINWINDOW_H

在这里插入图片描述

13.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "PluginInterface.h"
#include <QDir>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    if(loader.isLoaded())
    {
        loader.unload();
    }
    delete ui;
}


void MainWindow::on_pushButton_clicked()
{
    QDir dir("F:/QT_code/1study/tetsPlugIn/Debug/debug");
    //QDir dir(qApp->applicationDirPath());//加载当前运行目录
    qDebug("目录1:%s",dir.path().toUtf8().constData());
    loader.setFileName(dir.filePath("PluginDemo.dll"));//将加载器的目录加载进来
    qDebug("目录2:%s",dir.filePath("PluginDemo.dll").toUtf8().constData());
    if(!loader.load())
    {
        qDebug("Failed to load loader");
        QMessageBox::critical(this,"Tips",loader.errorString());
        return ;
    }
    //实例化
    QObject *plugin = loader.instance();
    qDebug() << __FUNCTION__ << loader.errorString();
    if(plugin==NULL)
    {
        qDebug("loader.instance() is null");
        return;
    }
    qDebug("Success1");
    PluginInterface *pi = qobject_cast<PluginInterface *>(plugin);
    if(pi)
    {
        QWidget * w = pi->getWidget();
        qDebug("Success2");
        if(w)
        {
            ui->tabWidget->addTab(w,"hello plugin");
            qDebug("Success3");
        }
        qDebug("Success4");
    }else{
        qDebug("pi is NULL");
    }
}



在这里插入图片描述

补充:这个博主我真的栓q,很多细节没有讲

1. error: Undefined interface=>这个非常重要,在沟通插件工程与主框架工程的这个头文件中,必须加上这个!!!

Q_DECLARE_INTERFACE(PluginInterface,PluginInterfaceIID)//此宏必须定义,否则外部程序会报错。
在这里插入图片描述

2. error: C2039: “qt_metacall”

3.error: C2039: “staticMetaObject”: 不是 “PluginInterface” 的成员

4.error: C2338: qobject_cast requires the type to have a Q_OBJECT macro

由于在使用qobject_cast时,类型没有使用Q_OBJECT宏定义导致的

5.error: C2440: “static_cast”: 无法从“QObject *”转换为“T”

还是PluginInterface *pi = qobject_cast<PluginInterface *>(loader.instance());报错
解决:PluginInterface 要继承QObject
在这里插入图片描述

效果

运行

在这里插入图片描述

点击

在这里插入图片描述
在这里插入图片描述

代码结构

在这里插入图片描述

代码地址

代码地址

教程

教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/121745.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unix环境高级编程-学习-02-进程环境之进程终止、命令行参数、环境表、C程序的存储空间布局

目录 一、环境信息 二、声明 三、进程终止 1、情况分类 2、退出函数 3、退出实验 &#xff08;1&#xff09;main声明int和调用return值 &#xff08;2&#xff09;main声明int和不调用return &#xff08;3&#xff09;main声明不int和不调用return 4、atexit 5、at…

SpringBoot加载测试类属性和配置说明

一、项目准备 1.创建项目 2.配置yml文件 test:name: FOREVERlove: sing二、测试类属性 1.Value 说明&#xff1a;读取yml中的数据。 package com.forever;import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; import org.spr…

Linux中固定ip端口和修改ip地址

一&#xff0c;更改虚拟网络编辑器 1&#xff0c;首先启动VMware&#xff0c;选择自己要更改ip或固定ip的虚拟机&#xff0c;并找到虚拟网络配编辑器&#xff0c;点击进入 2&#xff0c;进入之后需要点击右下角获取管理员权限后才能修改&#xff0c;有管理员权限之后图片如下 …

TSINGSEE青犀车辆违停AI算法在园区道路管控场景中的应用方案

一、背景与需求 园区作为企业办公、生产制造的重要场所&#xff0c;主要道路车辆违停等违规行为会对园区的安全造成隐患&#xff0c;并且在上下班高峰期内&#xff0c;由于发现不及时&#xff0c;车辆违停行为会造成出入口拥堵现象&#xff0c;这也成为园区管理的棘手问题。 …

C++入门(二)

前言 我们上一期介绍了什么是C&#xff0c;命名空间、输入输出、以及缺省参数。本期我们来继续介绍C的入门知识&#xff01; 本期内容介绍 函数重载 引用 内联函数 auto关键字 范围for 指针空值nullptr 目录 前言 本期内容介绍 一、函数重载 什么是函数重载&#xff1f; …

Apple :苹果将在明年年底推出自己的 AI,预计将随 iOS 18 一起推出

本心、输入输出、结果 文章目录 Apple &#xff1a;苹果将在明年年底推出自己的 AI&#xff0c;预计将随 iOS 18 一起推出前言三星声称库克相关图片弘扬爱国精神 Apple &#xff1a;苹果将在明年年底推出自己的 AI&#xff0c;预计将随 iOS 18 一起推出 编辑&#xff1a;简简单…

Java关于由子类构造器生成的父类对象的反射问题

Java关于由子类构造器生成的父类对象的反射问题 问题概括一、案例准备二、问题描述 问题概括 提示&#xff1a;这里我就不绕圈子直接描述&#xff1a; Java中由子类构造器生成的父类的getclass.getName不是父类的类名而是子类的类名&#xff0c;因此不可以用子类构造器生成的…

2023年【安全员-B证】新版试题及安全员-B证免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-B证新版试题参考答案及安全员-B证考试试题解析是安全生产模拟考试一点通题库老师及安全员-B证操作证已考过的学员汇总&#xff0c;相对有效帮助安全员-B证免费试题学员顺利通过考试。 1、【多选题】下列哪些属…

HTML表格学习

HTML学习笔记二 HTML表格&#xff1a; HTML 表格由 标签来定义。 HTML 表格是一种用于展示结构化数据的标记语言元素。 tr&#xff1a;表示表格的一行。td&#xff1a;表示表格的数据单元格。th&#xff1a;表示表格的表头单元格。 数据单元格可以包含文本、图片、列表、段…

Scala爬虫实战:采集网易云音乐热门歌单数据

导言 网易云音乐是一个备受欢迎的音乐平台&#xff0c;汇集了丰富的音乐资源和热门歌单。这些歌单涵盖了各种音乐风格和主题&#xff0c;为音乐爱好者提供了一个探索和分享音乐的平台。然而&#xff0c;有时我们可能需要从网易云音乐上获取歌单数据&#xff0c;以进行音乐推荐…

8086读取键盘-磁盘输入

文章目录 前言1.从键盘读数据2.磁盘读数据 前言 想过一个问题没有&#xff0c; 8086是如何从键盘中接受输入的&#xff1f; 8086如何将字符在显示器上显示的&#xff1f; 8086如何从磁盘中读取数据的&#xff1f; 上面的问题都是没有操作系统的时候&#xff0c;比如bios的那段…

Hive 知识点八股文记录 ——(一)特性

Hive通俗的特性 结构化数据文件变为数据库表sql查询功能sql语句转化为MR运行建立在hadoop的数据仓库基础架构使用hadoop的HDFS存储文件实时性较差&#xff08;应用于海量数据&#xff09;存储、计算能力容易拓展&#xff08;源于Hadoop&#xff09; 支持这些特性的架构 CLI&…

python解析xmind统计测试用例/测试点 个数及执行情况

前言&#xff1a;统计的是每个分支最后一个节点的状态 xmind版本 23.0911172 标记打开位置 标记规则如下 解释&#xff1a; res {"total": 0, "pass": 0, "fail": 0, "no_result": 0, "unfinished": 0, "now_fail…

SUSE 12双网卡绑定

原创作者&#xff1a;运维工程师 谢晋 SUSE 12双网卡绑定 客户环境及需求网卡绑定 客户环境及需求 客户一台物理机安装了SUSE 12的操作系统&#xff0c;需要将ETH5和ETH7双网卡聚合为一块虚拟网卡&#xff0c;以保证一块网卡故障不会影响系统正常运行。 网卡绑定 输入命令c…

C++冒号的作用域

当同时定义了一个全局变量a和局部变量a&#xff1a; 结果输出了局部变量的10&#xff0c;因为程序遵循就近原则。 :: 代表全局作用域 如果想无视就近原则&#xff0c;打印全局变量的a&#xff0c;就在输出时把a的前面加两个冒号。 ::

机器视觉目标检测 - opencv 深度学习 计算机竞赛

文章目录 0 前言2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 0 前言 &#x1f5…

推荐能用ios端磁力下载工具

关于ios端磁力下载工具&#xff0c;之前的文章给大家介绍过2个&#xff0c;分别是雷电下载和闪电下载。但是如今因为不可抗力和苹果商店对于磁力下载和云盘功能的限制&#xff0c;目前这两款工具已经不能够使用了。也就是说免费的下载工具已经没有了&#xff0c;毕竟实现ios端这…

Ubuntu 20.04源码安装git 2.35.1

《如何在 Ubuntu 20.04 上从源代码安装 Git [快速入门]》和《如何在 Ubuntu 20.04 上安装 Git》是我参考的博客。 https://git-scm.com/是git官网。 lsb_release -r看到操作系统版本是20.04。 uname -r看到内核版本是5.4.0-156-generic。 sudo apt update更新一下源。 完…

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)STM32G0控制EMW3080实现IoT功能

项目描述&#xff1a;该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程&#xff1b;硬件环境&#xff1a;单片机为STM32G030C8T6&#xff1b;物联网模块为EMW3080V2-P&#xff1b;网联网模块的开发板为MXKit开发套件&#xff0c;具体型号为XCH…

【RPC】前传

前传 本地程序用的go语言&#xff0c;想把main.go程序当中一些计算工作放到服务器上进行&#xff0c;而只需要把结果给我即可。由于平台上暂时不能运行Go代码&#xff0c;所以写的是python文件。 1、主要是使用ssh依赖进行连接&#xff0c;但是大概率是需要手动添加的&#xf…