Qt插件使用学习笔记PART2

用另一种方式实现Qt的插件制作与使用,这种方式的想法是这样的:

AbstractDevice(即两个device的父类)被做成一个动态链接库,用包含头文件与在工程文件中定义LIBS关键字来把其做成user_interface与两个device都可以使用的动态链接库,注意是动态链接库,不是插件。在具体细节实施之前,我了解到了几个重要信息:

1. interface也可以定义成一个类里并不全是纯虚函数,比如我这个例子里用Qt的宏把AbstractDevice这个类定义成了一个interface。

2.根据MSDN的 Dynamic-Link library的一个介绍文档:

https://msdn.microsoft.com/en-us/library/ms682586(v=vs.85).aspx#standard_search_order_for_desktop_applications

  • If a DLL with the same module name is already loaded in memory, the system uses the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
  • If the DLL is on the list of known DLLs for the version of Windows on which the application is running, the system uses its copy of the known DLL (and the known DLL's dependent DLLs, if any). The system does not search for the DLL. For a list of known DLLs on the current system, see the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs.

根据windows查找的顺序,动态库一般是要放在可执行文件的所在的目录下的,当动态库已经被加载了(应该是根据动态库文件名判断),不会反复加载。例如我在运行可执行文件时加载了动态库,当插件还是需要加载同一个动态库的时候,不会重新加载。

下面图片是我工程的一个大概介绍:


user_interface这个子项目只进行了很小的修改,因为我重新定义了device的interface。项目中,AbstractDevice是一个动态库,而FLOODCONTROL和PRECHARGE是我所制作的插件。下面开始上代码

abstract_device.pro:

QT       -= gui
QT+= core serialport


TARGET = abstract_device
TEMPLATE = lib

DEFINES += ABSTRACT_DEVICE_LIBRARY

SOURCES += abstract_device.cpp

HEADERS += abstract_device.h\
        abstract_device_global.h
INCLUDEPATH  += ../../user_interface

DESTDIR       = ../../plugins
可以看到我没有定义CONFIG为plugin。

abstract_device.h:

#ifndef DEVICE
#define DEVICE
#include <QObject>
#include <QTimer>
#include <QByteArray>
#include <QString>
#include <QSerialPort>
#include <QByteArray>
//#include "device_interface.h"
#include "global.h"
#include "abstract_device_global.h"

class ABSTRACT_DEVICESHARED_EXPORT AbstractDevice:public QObject
{

    Q_OBJECT
public:


    explicit AbstractDevice(QObject *parent=0);
  //  bool getPortDiscon();
   virtual void sendData(double info, sendCommands command)=0;
    bool isOpen();
    virtual void sendReset()=0;
     void closePort();
    void openPort(QString port_name);
    double getCvVal();
    double getFcVal();
    double getEcVal();
    double getFvVal();
    void setCvVal(double value);
    void setFcVal(double value);
    void setEcVal(double value);
    void setFvVal(double value);
  //  void flushPort();
    virtual void getVersion()=0;
    deviceState currentState();


signals:
    void sendInfo(double value, readCommands command);
    void sendMessage(double value,  sendCommands command);
    void sendConnectionError();
    void versionInfo(int ver_1 ,int ver_2);
    void needReset();
    void commandError();
    void stateSignal(deviceState state);

public slots:
    virtual void sensorDisplay()=0;
   //  void checkConnection();
      void connectionError();
     // void checkConnection2();


   // void closingPort();
protected:
      QSerialPort *port;
      deviceState state;
      QTimer* connect_timer;


private:
    QTimer* second_connect_timer;


    double cvVal;
    double fcVal;
    double ecVal;
    double fvVal;
};
Q_DECLARE_INTERFACE(AbstractDevice, "deviceinterface")
#endif // DEVICE
这里我用了Qt的宏来把interface declare 了。在abstract_device_global.h里定义的宏ABSTRACT_DEVICE_EXPORT也用在了这里,源文件是毫无变化的。

我用这个代码生成了一个动态库,在user_interface项目里的可执行文件要加载这个动态库,然后我的两个插件也要加载这个动态库,由上面粘贴的msdn的信息可得知我的动态库被exe文件加载了,插件就不会去重新加载了。


floodcontrol.pro:

QT       -= gui
QT   +=core serialport
TARGET = floodcontrol
TEMPLATE = lib
CONFIG +=plugin

DEFINES += FLOODCONTROL_LIBRARY

SOURCES += floodcontrol.cpp

HEADERS += floodcontrol.h\

INCLUDEPATH  += ../../user_interface\
                ../abstract_device

win32-g++*:LIBS+= D:\voltage_controller_redo_out\plugins\libabstract_device.a
#win32-msvc*:LIBS+= D:\msvc_out\plugins\abstract_device.lib
#LIBS += -LD:\msvc_out\plugins -labstract_device

DESTDIR       = ../../plugins

这里我把项目的链接库用LIBS关键字定义了,CONFIG定义成了PLUGIN。

floodcontrol.cpp:

#ifndef FLOODCONTROL_H
#define FLOODCONTROL_H

#include "abstract_device.h"
#include <QList>
#include <QQueue>
#include <QVector>
#include <QFile>

class FloodControl: public AbstractDevice
{
    Q_OBJECT
    Q_INTERFACES( AbstractDevice )
      Q_PLUGIN_METADATA(IID "deviceinterface")


public:


    explicit FloodControl(QObject *parent=0);
    void sendData(double info, sendCommands command);
    void sendReset();
    void getVersion();
    QString deviceName();

    //void sendReset();
   // void getVersion();
signals:

   // void sendConnectionError();
   // void versionInfo(int ver_1,int ver_2);


public slots:

  //  void checkConnection();
   // void connectionError();
    void sensorDisplay();
    void autoSend();
   //void sensorDisplay();
  //  void checkConnection();
  //  void connectionError();

private:



   //   QTimer *connect_timer;
    //    int buffer_pos;
    QQueue<QString> commandBuffer;
    QVector<QString> normalCommands;

    bool sendFlag;
    QTimer *sendTimer;
    int normalComPosition;
    QTimer *autoTimer;
     QTimer *connect_timer;
     QByteArray comm;
     QFile *file;

};

#endif // FLOODCONTROL_H

这个是插件的制作所需要的宏,运行在宏Q_OBJECT之后。

在user_interface项目中我也运用了定义链接库,包含头文件的方式来构建项目。值得注意的是,动态链接库文件和可执行文件(.exe)放在同一个目录下,对新手来说很方便,不用考虑查找顺序和方式带来的加载问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值