Qt 4 插件开发(3)

上一章我们已经有了一个MonsterInterface接口。现在,让我们使用这个接口来创建一个怪物插件 Troll(食人怪)。

首先还是要给出 Troll 的 pro 文件:

QT       -= gui

TARGET = Troll
TEMPLATE = lib

DEFINES += TROLL_LIBRARY

DESTDIR = ../plugins

MOC_DIR     = troll
OBJECTS_DIR = troll

INCLUDEPATH += ../GameSystem

SOURCES += troll.cpp

HEADERS += troll.h\
        Troll_global.h

下面我们来分析下这个文件。首先,我们的插件不需要 GUI 部分(因为前面说过,为简便起见,我们去除掉界面),所以会有QT -= gui。TARGET 代表生成的插件的名字,这里就是 Troll。TEMPLATE 设置为 lib。只要是编写插件,我们的 TEMPLATE 就是 lib。DEFINES 代表在编译时添加的宏。这里我们引入一个宏TROLL_LIBRARY,具体作用我们会在后文详细介绍。目的文件夹 DESTDIR 设置为 ../plugins。这里的 .. 是相对于编译输出目录,也就是说,我们需要在 Qt Creator 的 Project 的 Building Path 设置为 E:\Qt\game\build\troll(回忆下上一章,我们将 GameSystem 的构建目录设置为 E:\Qt\game\build\sys,这需要我们手动设置,以保证它们会生成在同一个目录下,而 GameSystem 的构建目录是 build/sys;Troll 则是 build/troll。虽然这部分不是必须的,但是这样的设置可以让生成的插件以及主程序在正确的目录下,免得我们手动去复制)。DESTDIR = ../plugins,也就是相对于 build/troll 向上一级的 plugins 目录,即 build/plugins 这个目录。MOC_DIR 和 OBJECTS_DIR 指定了 moc 和 .obj 的输出目录,这里不再赘述。INCLUDEPATH 说明编译这个工程需要引入 ../GameSystem 目录下的头文件,也就是 monsterinterface.h。这么做的好处是,我们的主程序和插件共用一个接口头文件,不需要将这个头文件再复制到插件目录。最后就是插件所需要的头文件和源代码文件。

最简单的 Troll.global.h 其实是 Qt Creator 自动生成的。我们来看看里面有什么东西:

#ifndef TROLL_GLOBAL_H
#define TROLL_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(TROLL_LIBRARY)
#  define TROLLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TROLLSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // TROLL_GLOBAL_H

这个头文件很简单,其实是根据是否定义了TROLL_LIBRARY宏来将TROLLSHARED_EXPORT重新定义。TROLL_LIBRARY这个宏就是我们在 pro 的 DEFINES 中定义的。如果TROLL_LIBRARY已经定义,则TROLL_EXPORT定义为Q_DECL_EXPORT,否则的话则是Q_DECL_IMPORT。由于我们在 Troll 插件的 pro 中定义了TROLL_LIBRARY宏,那么TROLLSHARED_EXPORT会被展开为Q_DECL_EXPORT

而 troll.h 则是这样的:

#ifndef TROLL_H
#define TROLL_H

#include <QObject>
#include "Troll_global.h"
#include "monsterinterface.h"

class TROLLSHARED_EXPORT Troll : public QObject, public MonsterInterface
{
    Q_OBJECT
    Q_INTERFACES(MonsterInterface)
public:
    Troll();

    QString name() const
    {
        return "Troll";
    }
};

#endif // TROLL_H

类 Troll 前面有TROLLSHARED_EXPORT修饰,而前面说了这个宏将会展开为Q_DECL_EXPORT。我们可以认为,由Q_DECL_EXPORT修饰的类,就是被暴露(export)出的类。也就是说,现在在我们的插件中,由TROLLSHARED_EXPORT修饰的 Troll 类已经被暴露出,可以由主程序访问到。

这个类继承了QObject所有的插件都必须继承自 QObject。然后,插件要声明它提供哪些服务,也就是它会实现那些接口。这里就是我们的怪物接口MonsterInterface。下面除了Q_OBJECT宏(这是QObject子类所要求的),还需要使用Q_INTERFACES告诉 Qt,这个类实现了哪些接口。MonsterInterface接口要求有一个name()函数,因此我们就简单的定义一个name()

Troll 的实现文件则更简单:

#include <QtPlugin>
#include "troll.h"

Troll::Troll()
{
}

Q_EXPORT_PLUGIN2("Troll", Troll)

因为我们的接口很简单,所以 cpp 文件中基本没有什么东西。最主要的是 cpp 文件最后一行Q_EXPORT_PLUGIN2这个宏。这个宏要求两个参数,第一个是一个字符串,代表插件的名字;第二个是插件类。

至此,我们就完成了插件 Troll。下面将其编译一下。如果没有错误,那么应该在 build 目录下有一个 plugins 目录,Troll.dll(Windows)就会出现在这个目录中。

2 Comments

  1. 小鹿 2014年7月21日
    • 豆子 2014年7月25日

Leave a Reply