1

最近在修改Meshlab的源代码,使其能够展示我们自己的数据格式。看Meshlab源代码的时候发现它的架构非常漂亮,因此决定好好研究一下,后面其他代码重构的时候可以参考这个架构。

Meshlab使用Qt实现,整体工程由主窗体和多个子功能模块组成,使用Subdirs工程文件进行子项目的组织。各个子模块与主窗体是松耦合的,编译时不相互依赖,编译完成之后主窗体加载模块的动态链接库,如果没有相应的库或者加载失败则没有相应功能,而不影响其他功能。

我编译时使用如下的一个Subdirs工程文件

TEMPLATE=    subdirs
CONFIG+=     ordered

SUBDIRS=    common \
            meshlab \
            meshlabplugins/io_rawdata

一共编译三个子工程,common,meshlab以及io_rawdata,前两个工程是Meshlab的基础,是必需编译的,最后一个是可选的功能模块。下面分别介绍一下这三个子工程。

common工程编译出来是一个静态库,其他所有的工程都需要链接这个静态库common.lib,这个工程只是负责接口的声明,功能由具体的模块实现,由主窗体调用。比如我编写如下的一个接口声明一个纯虚函数testFunc,这个函数会由io_rawdata实现,并在meshlab中被调用。

class RawDataIOInterface
{
public:
    RawDataIOInterface(){}

    virtual int testFunc()=0;
};

#define RawDataIOInterface_IID "com.dinglufe.RawDataIOInterface"
Q_DECLARE_INTERFACE(RawDataIOInterface,RawDataIOInterface_IID)

meshlab工程是主窗体部分,也是整个工程的核心,负责界面和交互,其他的一些工程通过加载动态链接库使用。比如可以加载io_rawdata.dll使用RawDataIOInterface中声明的testFunc,测试代码如下

#include <common/rawdataiointerface.h>
#include <QPluginLoader>
#include <QDebug>

void testRawDataFunc()
{
    QPluginLoader loader("plugins/io_rawdata.dll");
    QObject *plugin = loader.instance();
    RawDataIOInterface *iRawDataIO = qobject_cast<RawDataIOInterface *>(plugin);

    qDebug()<<iRawDataIO->testFunc();
}

最后是io_rawdata工程,这是一个工程模块,这个模块负责io相关的一些功能,比如读取我们自己的文件格式,同样依赖于common工程获取相应的接口,然后实现其中声明的功能,比如如下一段测试代码

#include <common/rawdataiointerface.h>

class RawDataIO : public RawDataIOInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID RawDataIOInterface_IID)
    Q_INTERFACES(RawDataIOInterface)

public:
    RawDataIO():RawDataIOInterface(){}

    int testFunc(){return 1;}
};

实现了RawDataIOInterface所声明的testFunc函数。

当然了,以上说的这些东西都只不过是QPlugin的使用简介而已。关于代码的组织,meshlab还有很多不错的设计,可以去阅读一下它的代码


dinglufe
83 声望4 粉丝