This is a repost from my previous Qt learning series, based on Qt 4.3.
本篇继续介绍Qt的高级特性:
1. L&F Customization (自定义观感)
这个东西也就是传说中的skining, 换皮肤(画皮? – -). 如果你用过mfc或者java来实现控件的换肤功能的话, 那你一定觉得那是最恐怖的事情, 简直是一张张的图片往上贴啊… Qt也可以这么做, 但是提供了2种更聪明方便的方法:
a) qss (Qt Style Sheet): 这个东西灵感来源于html的css (书上也的是”inspired by”, 我就直译啦). 也就是说用qss来控制观感, 逻辑什么的还是用C++代码. 然后我就不介绍啦, 看看官方文档吧: http://doc.trolltech.com/4.3/stylesheet-syntax.html
b) 子类化QStyle
类: Qt把所有观感相关的数据都抽象到了QStyle
或者它的子类中, 我们要支持一个新的L&F的话, 只要继承这个类或者其子类, 重载一些函数就可以了. 这个我也不详细说啦, 书上也几乎都是抄的官方文档: http://doc.trolltech.com/4.3/style-reference.html
2. 插件框架:
我们来想一下, 对于插件一般的实现方法. 能想到的大概是这样. 写一堆dll, 这些dll都提供统一的export接口函数.
Qt的做法做法是差不多的, 只是在中间又提供了一层跨平台的抽象(shared dll在各个平台的实现都是不一样的嘛) 以及精简接口. 用PE Explorer可以看到所有的Qt plugin都只export了2个函数: qt_plugin_instance()
, qt_plugin_query_verification_data()
, 不过这两个函数具体是怎么调用的还没survey过.
Qt的plugin可以分为两类: Qt本身的plugin和自己写的application的plugin.
Qt的plugin可以implement 已有的接口. 比如可以implement QStylePlugin
接口把style作为plugin, 可以implement QImageIOPlugin
接口扩展Qt可以识别的图片格式, 等等. 这个就不说了.
Qt的plugin还可以implement自定义的接口. 下面说一下大概的步骤:
a) 首先定义一个interface的类, 定义virtual functions, 最后调用Q_DECLARE_INTERFACE
宏. 一般的interface都会提供这样的结构, 一个keys()接口说明当前plugin可以创建哪些object, 然后是一个创建object的函数(这里我写的doSomething()
是同样的意思). 代码如下:
1 2 3 4 5 6 7 8 |
class QXxxInterface { public: virtual ~QXxxInterface() { } virtual QStringList keys() const = 0; virtual QXxx doSomething(QString key) = 0; }; Q_DECLARE_INTERFACE(QXxxInterface, "com.ycool.gonwan.QXxxInterface/1.0") |
b) Implement 这个interface, 以下分别是*.h文件和*.cpp文件:
1 2 3 4 5 6 7 8 9 10 11 |
// .h class QMyXxxPlugin : public QObject, public QXxxInterface { Q_OBJECT Q_INTERFACES(QXxxInterface) public: QStringList keys() const; QXxx doSomething(QString key); };[/code] [code lang="cpp"][/code]// .cpp Q_EXPORT_PLUGIN2(myxxxplugin, QMyXxxPlugin) |
*.h中的Q_INTERFACES
宏用来告诉Qt的meta system这个类implement了哪个接口. 而*.cpp中Q_EXPORT_PLUGIN2
宏是用来export dll接口的, 放在所有类成员函数之外调用就行了.
c) 调用, Qt提供了一个QPluginLoader
类专门用来load插件. 依据上面现有的代码, 我们可以如下调用:
1 2 3 4 5 6 7 8 |
QPluginLoader loader("./plugins/myxxxplugin.dll"); if (QXxxInterface *interface = qobject_cast<QXxxInterface *>(loader.instance())) { foreach (QString key, interface.keys()) { interface.doSomething(key); } } |
以上代码并不涉及具体的plugin的操作, 否则就不能叫做plugin了呵呵.
官方文档: http://doc.trolltech.com/4.3/plugins-howto.html