编写Qtopia插件

编写Qtopia插件

l        

l        

l        

l        

l        

l        

简介


Qtopia下的插件是通过COM-like层来实现的,写一个Qtopia插件一般步骤如下:
1
、写出插件将提供的功能;
2
、子类化你需要写的插件的接口;
3
、提供接口方法的实现;
4
、建立一个插件的实例。
下面是写的一个插件必须遵守的规则:
1
、由于moc的实现细节,在你的插件里任何QObject的子类都必须拥有一个唯一的名字,以防止两个插件之间发生冲突,这是非常重要的一点。为所有的类(包括内在类)加上一个唯一的前缀,可以很好的实现这一规则。举个例子,如果你的插件"foo"有一个QObject的子类helper,你需要将它命名为FooHelper,这样比Helper更安全。
2
、插件不能泄露内存。一个插件可以在任何时候卸载,所以,在插件接口析构的时候,一定要清空所有使用过的内存。

 

书写功能性


假定如下一个插件接口:

//{05E 0A 4AB-DDC5-4449 -85A 9-828100DE 00A 9}
#ifndef IID_WidgetPlugin
#define IID_WidgetPlugin QUuid( 0x05e 0a 4ab, 0xddc5, 0x4449, 0x85, 0xa9, 0x82, 0x81, 0x00, 0xde, 0x00, 0xa9)
#endif

struct WidgetPluginInterface : public QUnknownInterface
{
    virtual QWidget *widget( QWidget *parent ) = 0;
    virtual QString name() const = 0;
};

这只是一个提供了插件名和父窗口组件的简单插件。
IID_WidgetPlugin
给这个接口定义了一个唯一的ID
我们写的这个插件提供了一个组件用于在它的中央画一个椭圆,下面这是这个插件提供功能的实现代码。

class EllipseWidget : public QWidget
{
    Q_OBJECT
public:
    EllipseWidget( QWidget *parent=0 ) : QWidget( parent, "Ellipse" )
    {
    }

protected:
    void paintEvent( QPaintEvent * )
    {
        QPainter p( this );
        p.drawEllipse( rect() );
    }
};

 

子类化接口


现在你可以子类化WidgetPluginInterface
struct CirclePlugin : public WidgetPluginInterface
{
public:
    virtual QWidget *widget( QWidget *parent );
    virtual QString name() const;

    QRESULT queryInterface( const QUuid&, QUnknownInterface** );
    Q_REFCOUNT

protected:
    CircleWidget *w;
    ulong ref;
};

CirclePlugin结构中有两点我们必须注意的地方:
1
queryInterface()函数允许插件加载器请求插件实现的接口。
2
Q_REFCOUNT是一个引用计数的宏,这个宏用提供的ulong型的ref变量进行计数。

 

接口的实现


ref
必须在构造函数中用0进行初始化。
CirclePlugin::CirclePlugin()
    : w(0), ref(0)
{
}

CirclePlugin::~CirclePlugin()
{
    delete w;
}

queryInterface()函数可以用下面的示例代码实现:
QRESULT CirclePlugin::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
{
    *iface = 0;
    if ( uuid == IID_QUnknown )
        *iface = this;
    else if ( uuid == IID_WidgetPlugin )
        *iface = this;
    else
        return QS_FALSE;

    (*iface)->addRef();
    return QS_OK;
}

一个插件可以提供多个接口,但所有的插件都至少要提供QUnknowInterface接口。.

wiget()函数返回一个组件。
QWidget *CirclePlugin::widget( QWidget *parent )
{
    if ( !w )
        w = new CircleWidget( parent );
    return w;
}


name()
函数返回插件名。
QString CirclePlugin::name()
{
    return qApp->translate( "WidgetPlugin", "Circle" );
}

 

建立实例


你也需要用下面的示例代码实例化这个组件插件:

Q_EXPORT_INTERFACE()
{
    Q_CREATE_INSTANCE( CirclePlugin )
}

 

装载插件


推荐使用PluginLoader类来进行加载插件,PluginLoader类简单化了插件的列举和安装,并且它也给安全模式下启动的系统提供了安全的case
PluginLoader loader( "Widgets" );
QStringList list = pluginLoader.list();
QStringList::Iterator it;
QValueList<WidgetPluginInterface*> widgetsList;
for ( it = list.begin(); it != list.end(); ++it ) {
    WidgetPluginInterface *iface = 0;
    if ( pluginLoader.queryInterface( *it, IID_WidgetPlugin, (QUnknownInterface**)&iface ) == QS_OK && iface ) {
        widgetsList.append( iface );
    }
}
PluginLoader
类一般认为插件安装到$QPEDIR/plugins/type目录下。

 

你可能感兴趣的:(struct,object,delete,iterator,Class,interface)