在之前的文章中,有介绍通过QProcess的方式启动QWidget应用,然后将其窗口嵌入到其他的qt应用中,作为子窗口使用.这篇文章主要介绍qt插件的方式将QWidget应用的窗口封装为插件,然后作为其他Qt应用中的子窗口使用.
插件优点:
与主程序为同一个进程,免去了进程间繁琐的通信方式,在不同进程间通信时,需要有一套协议来保证数据的及时性及稳定性.比较繁琐,而插件的方式,通过插件接口文件来进行通信,在接口文件中定义API,
接口文件(定义为纯虚类)(主程序通过接口文件来访问该插件,插件通过继承该接口,重写所有纯虚函数)
cpp
#pragma once
#include <QtPlugin>
QT_BEGIN_NAMESPACE
class QString;
class QWidget;
QT_END_NAMESPACE
//定义视觉检测接口
class InterfaceVisionMeasure
{
public:
virtual ~InterfaceVisionMeasure() = default;
/// <summary>
/// 创建视觉窗口对象指针
/// </summary>
/// <param name="iLanguage">0为英文,1为中文</param>
/// <param name="parent">父对象</param>
/// <returns>窗口指针</returns>
virtual void* CreatWindow(int iLanguage, QWidget* parent = nullptr) = 0;
/// <summary>
/// 获取对应序号轴编码器坐标
/// </summary>
/// <param name="GetAxisEncVal">回调对象</param>
virtual void RegisterGetAxisEncVal(const std::function<void(int, double&)>& GetAxisEncVal) = 0;
/// <summary>
/// 获取对应序号轴规划位置坐标
/// </summary>
/// <param name="GetAxisPrfVal">回调对象</param>
virtual void RegisterGetAxisPrfVal(const std::function<void(int, double&)>& GetAxisPrfVal) = 0;
/// <summary>
/// 获取内部变量的值
/// </summary>
/// <param name="GetVariableInVal">回调对象</param>
virtual void RegisterGetVariableInVal(const std::function<void(int, double&)>& GetVariableInVal) = 0;
/// <summary>
/// 设置内部变量的值
/// </summary>
/// <param name="SetVariableInVal">回调对象</param>
virtual void RegisterSetVariableInVal(const std::function<void(int, const double&)>& SetVariableInVal) = 0;
/// <summary>
/// 设置当前测量文件路径(测量文件)
/// </summary>
/// <param name="dir">测量文件路径</param>
virtual void SetCurrentMeaureFile(const QString& dir) = 0;
/// <summary>
/// 开启测量
/// </summary>
/// <param name="indexMain">工序号</param>
/// <param name="IndexSub">工序号中的子序号</param>
virtual void StartMeasureProcess(int indexMain, int IndexSub) = 0;
/// <summary>
/// 测量结果返回到主程序
/// </summary>
/// <param name="MeasureResult">回调对象</param>
virtual void RegisterMeasureResult(const std::function<void(const int&, const QStringList&, const QVector<double>&)>& MeasureResult) = 0;
/// <summary>
/// 创建测量文件(编辑文件)
/// </summary>
/// <param name="dir">创建路径</param>
/// <returns>0为正常,非0为失败</returns>
virtual int NewMeasureFile(const QString& dir)=0;
/// <summary>
/// 打开测量文件(编辑文件)
/// </summary>
/// <param name="dir">打开路径</param>
/// <returns>0为正常,非0为失败</returns>
virtual int OpenMeasureFile(const QString& dir) = 0;
/// <summary>
/// 另存为测量文件(编辑文件)
/// </summary>
/// <param name="srcDir">源文件路径</param>
/// <param name="desDir">目标文件路径</param>
/// <returns>0为正常,非0为失败</returns>
virtual int SaveAsMeasureFile(const QString& srcDir, const QString& desDir) = 0;
/// <summary>
/// 设置当前显示页
/// </summary>
/// <param name="indexMain">对应工序页, -10为找中心,-11为对焦</param>
/// <param name="indexSub">对应工序页中的第几页</param>
/// <returns>0为成功, </returns>
virtual int SetShowMeasurePage(int indexMain, int indexSub)=0;
/// <summary>
/// 获取当前测量工程工序列表(测量文件)
/// </summary>
/// <param name="listType">工序列表</param>
/// <returns>0为成功</returns>
virtual int GetCurMeasureProgram(QVector<int>& listType)=0;
};
QT_BEGIN_NAMESPACE
#define Interface_VisionMeasure_IID "Demina.Nc.VisionMeasureInterface/1.0"
Q_DECLARE_INTERFACE(InterfaceVisionMeasure, Interface_VisionMeasure_IID)
QT_END_NAMESPACE
重写接口类: h文件
cpp
#pragma once
#include <QObject>
#include "InterfacesVisionMeasure.h"
class qcDllVisionMeasure : public QObject, public InterfaceVisionMeasure
{
Q_OBJECT
Q_INTERFACES(InterfaceVisionMeasure)
Q_PLUGIN_METADATA(IID Interface_VisionMeasure_IID FILE "DllVisionMeasure.json")
public:
qcDllVisionMeasure(QObject* parent = nullptr);
~qcDllVisionMeasure() override;
/// <summary>
/// 创建视觉窗口对象指针
/// </summary>
/// <param name="parent">父对象</param>
/// <returns>窗口指针</returns>
void* CreatWindow(int iLanguage, QWidget* parent = nullptr) override;
/// <summary>
/// 获取对应序号轴编码器坐标
/// </summary>
/// <param name="GetAxisEncVal">回调对象</param>
void RegisterGetAxisEncVal(const std::function<void(int, double&)>& GetAxisEncVal) override;
/// <summary>
/// 获取对应序号轴规划位置坐标
/// </summary>
/// <param name="GetAxisPrfVal">回调对象</param>
void RegisterGetAxisPrfVal(const std::function<void(int, double&)>& GetAxisPrfVal) override;
/// <summary>
/// 获取内部变量的值
/// </summary>
/// <param name="GetVariableInVal">回调对象</param>
void RegisterGetVariableInVal(const std::function<void(int, double&)>& GetVariableInVal) override;
//设置内部变量的值
void RegisterSetVariableInVal(const std::function<void(int, const double&)>& SetVariableInVal) override;
/// <summary>
/// 设置当前测量文件路径
/// </summary>
/// <param name="dir">测量文件路径</param>
void SetCurrentMeaureFile(const QString& dir) override;
/// <summary>
/// 开启测量
/// </summary>
/// <param name="indexMain">工序号</param>
/// <param name="IndexSub">工序号中的子序号</param>
void StartMeasureProcess(int indexMain, int IndexSub) override;
/// <summary>
/// 测量结果返回到主程序
/// </summary>
/// <param name="MeasureResult">回调对象</param>
void RegisterMeasureResult(const std::function<void(const int&, const QStringList&, const QVector<double>&)>& MeasureResult) override;
/// <summary>
/// 创建测量文件
/// </summary>
/// <param name="dir">创建路径</param>
/// <returns>0为正常,非0为失败</returns>
int NewMeasureFile(const QString& dir) override;
/// <summary>
/// 打开测量文件
/// </summary>
/// <param name="dir">打开路径</param>
/// <returns>0为正常,非0为失败</returns>
int OpenMeasureFile(const QString& dir) override;
/// <summary>
/// 另存为测量文件
/// </summary>
/// <param name="srcDir">源文件路径</param>
/// <param name="desDir">目标文件路径</param>
/// <returns>0为正常,非0为失败</returns>
int SaveAsMeasureFile(const QString& srcDir, const QString& desDir) override;
/// <summary>
/// 设置当前显示页
/// </summary>
/// <param name="indexMain">对应工序页, -10为找中心,-11为对焦</param>
/// <param name="indexSub">对应工序页中的第几页</param>
/// <returns>0为成功, </returns>
int SetShowMeasurePage(int indexMain, int indexSub) override;
/// <summary>
/// 获取当前测量工程工序列表
/// </summary>
/// <param name="listType">工序列表</param>
/// <returns>0为成功</returns>
int GetCurMeasureProgram(QVector<int>& listType) override;
private:
//视觉界面对象指针
void* m_pMainWnd{};
};
在实现cpp中,封装QWidget窗口,创建其实例
cpp
#include "stdafx.h"
#include "qcDllVisionMeasure.h"
#include "qwaMeasureToolsVM.h"
qcDllVisionMeasure::qcDllVisionMeasure(QObject *parent)
:QObject(parent)
{
}
qcDllVisionMeasure::~qcDllVisionMeasure()
{
}
void* qcDllVisionMeasure::CreatWindow(int iLanguage, QWidget* parent)
{
qwaMeasureToolsVM* widget = new qwaMeasureToolsVM(iLanguage,true,parent);
m_pMainWnd =(void*) widget;
return m_pMainWnd;
}
//采用回调的方式实现,插件通过回调函数来获取,设置参数
//获取对应序号轴编码器坐标
void qcDllVisionMeasure::RegisterGetAxisEncVal(const std::function<void(int, double&)>& GetAxisEncVal)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->RegisterGetAxisEncVal(GetAxisEncVal);
}
}
//获取对应序号轴规划位置坐标
void qcDllVisionMeasure::RegisterGetAxisPrfVal(const std::function<void(int, double&)>& GetAxisPrfVal)
{
}
//获取内部变量的值
void qcDllVisionMeasure::RegisterGetVariableInVal(const std::function<void(int, double&)>& GetVariableInVal)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->RegisterGetVariableInVal(GetVariableInVal);
}
}
//设置内部变量的值
void qcDllVisionMeasure::RegisterSetVariableInVal(const std::function<void(int, const double&)>& SetVariableInVal)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->RegisterSetVariableInVal(SetVariableInVal);
}
}
/// <summary>
/// 设置当前测量文件路径
/// </summary>
/// <param name="dir">测量文件路径</param>
void qcDllVisionMeasure::SetCurrentMeaureFile(const QString& dir)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->SetCurrentMeaureFileByMainApp(dir);
}
}
/// <summary>
/// 开启测量
/// </summary>
/// <param name="indexMain">工序号</param>
/// <param name="IndexSub">工序号中的子序号</param>
void qcDllVisionMeasure::StartMeasureProcess(int indexMain, int IndexSub)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->StartMeasureProcessByMainApp(indexMain, IndexSub);
}
}
/// <summary>
/// 测量结果返回到主程序
/// </summary>
/// <param name="MeasureResult">回调对象</param>
void qcDllVisionMeasure::RegisterMeasureResult(const std::function<void(const int&, const QStringList&, const QVector<double>&)>& MeasureResult)
{
if (m_pMainWnd)
{
((qwaMeasureToolsVM*)m_pMainWnd)->RegisterMeasureResult(MeasureResult);
}
}
/// <summary>
/// 创建测量文件
/// </summary>
/// <param name="dir">创建路径</param>
/// <returns>0为正常,非0为失败</returns>
int qcDllVisionMeasure::NewMeasureFile(const QString& dir)
{
if (m_pMainWnd)
{
return ((qwaMeasureToolsVM*)m_pMainWnd)->NewMeasureFile(dir);
}
return -1;
}
/// <summary>
/// 打开测量文件
/// </summary>
/// <param name="dir">打开路径</param>
/// <returns>0为正常,非0为失败</returns>
int qcDllVisionMeasure::OpenMeasureFile(const QString& dir)
{
if (m_pMainWnd)
{
return ((qwaMeasureToolsVM*)m_pMainWnd)->OpenMeasureFile(dir);
}
return -1;
}
/// <summary>
/// 另存为测量文件
/// </summary>
/// <param name="srcDir">源文件路径</param>
/// <param name="desDir">目标文件路径</param>
/// <returns>0为正常,非0为失败</returns>
int qcDllVisionMeasure::SaveAsMeasureFile(const QString& srcDir, const QString& desDir)
{
if (m_pMainWnd)
{
return ((qwaMeasureToolsVM*)m_pMainWnd)->SaveAsMeasureFile(srcDir, desDir);
}
return -1;
}
/// <summary>
/// 设置当前显示页
/// </summary>
/// <param name="indexMain">对应工序页, -10为找中心,-11为对焦</param>
/// <param name="indexSub">对应工序页中的第几页</param>
/// <returns>0为成功, </returns>
int qcDllVisionMeasure::SetShowMeasurePage(int indexMain, int indexSub)
{
if (m_pMainWnd)
{
return ((qwaMeasureToolsVM*)m_pMainWnd)->SetShowMeasurePage(indexMain, indexSub);
}
return -1;
}
/// <summary>
/// 获取当前测量工程工序列表
/// </summary>
/// <param name="listType">工序列表</param>
/// <returns>0为成功</returns>
int qcDllVisionMeasure::GetCurMeasureProgram(QVector<int>& listType)
{
if (m_pMainWnd)
{
return ((qwaMeasureToolsVM*)m_pMainWnd)->GetCurMeasureProgram(listType);
}
return -1;
}
json接口描述json文件,放在头文件同目录
bash
{
"Type": ["BT150D"],
"Name": "VisionMeasure",
"Description": "this is vision measure tools.",
"Version": "1.0.0",
"Vendor": "demina"
}
设置工程生成为从exe改为dll
将qt插件功能启动
至此重新封装QWdiget结束, 等待生成的dll,将其复制到主程序的exe文件路径下即可.
在主程序中要做的工作,即通过接口文件 声明一个接口实例指针.
cpp
bool NcCoreQt::InitPluginVisionMeasure()
{
QString dir = qApp->applicationDirPath();
dir += "/VisionMeasure.dll";//视觉插件的dll
m_pPluginLoaderVM = new QPluginLoader(dir, this);
QObject* plugin = m_pPluginLoaderVM->instance();
//qDebug() << pluginLoader.metaData();
if (plugin) {
m_pInterfaceVM = qobject_cast<InterfaceVisionMeasure*>(plugin);
if (m_pInterfaceVM)
{
qInfo() << tr("Load vision measure interface successful");
return true;
}
}
else
{
qDebug() << m_pPluginLoaderVM->errorString();
}
return false;
}