简述
Qt 提供了两套用于创建插件的 API:
- High-Level API:用于扩展 Qt 本身(例如:自定义数据库驱动、图像格式、文本编解码、自定义样式等)
- Low-Level API:用于扩展 Qt 应用程序
例如,如果要编写自定义的 QStyle
子类,并且动态地加载 Qt 应用程序,则可以使用更高级别的 API。
由于较高级别的 API 构建在较低级别的 API 之上,所以某些问题对两者来说是共同的。
版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820
编写 Qt 扩展
要编写扩展 Qt 本身的插件,需要对适当的插件基类进行子类化,实现一些功能并添加一个宏。
下表总结了一些插件基类:
基类 | 目录 | Qt 模块 | 大小写敏感性 |
---|---|---|---|
QAccessibleBridgePlugin |
accessiblebridge | Qt GUI | 区分大小写 |
QImageIOPlugin |
imageformats | Qt GUI | 区分大小写 |
QPictureFormatPlugin (obsolete) |
pictureformats | Qt GUI | 区分大小写 |
QAudioSystemPlugin |
audio | Qt Multimedia | 区分大小写 |
QDeclarativeVideoBackendFactoryInterface |
video/declarativevideobackend | Qt Multimedia | 区分大小写 |
QGstBufferPoolPlugin |
video/bufferpool | Qt Multimedia | 区分大小写 |
QMediaPlaylistIOPlugin |
playlistformats | Qt Multimedia | 区分大小写 |
QMediaResourcePolicyPlugin |
resourcepolicy | Qt Multimedia | 区分大小写 |
QMediaServiceProviderPlugin |
mediaservice | Qt Multimedia | 区分大小写 |
QSGVideoNodeFactoryPlugin |
video/videonode | Qt Multimedia | 区分大小写 |
QBearerEnginePlugin |
bearer | Qt Network | 区分大小写 |
QPlatformInputContextPlugin |
platforminputcontexts | Qt Platform Abstraction | 区分大小写 |
QPlatformIntegrationPlugin |
platforms | Qt Platform Abstraction | 区分大小写 |
QPlatformThemePlugin |
platformthemes | Qt Platform Abstraction | 区分大小写 |
QGeoPositionInfoSourceFactory |
position | Qt Positioning | 区分大小写 |
QPlatformPrinterSupportPlugin |
printsupport | Qt Print Support | 区分大小写 |
QSGContextPlugin |
scenegraph | Qt Quick | 区分大小写 |
QScriptExtensionPlugin |
script | Qt Script | 区分大小写 |
QSensorGesturePluginInterface |
sensorgestures | Qt Sensors | 区分大小写 |
QSensorPluginInterface |
sensors | Qt Sensors | 区分大小写 |
QSqlDriverPlugin |
sqldrivers | Qt SQL | 区分大小写 |
QIconEnginePlugin |
iconengines | Qt SVG | 区分大小写 |
QAccessiblePlugin |
accessible | Qt Widgets | 区分大小写 |
QStylePlugin |
styles | Qt Widgets | 区分大小写 |
注意: 派生的插件默认存储在标准插件目录的子目录中,如果没有被存储在相应的目录中,Qt 将不会找到插件。
吐槽 Qt
你没看错,正在进行时 - 吐槽、吐槽、吐槽。。。
Qt 中有很多示例,其中有一个样式插件 - Style Plugin,可以正常运行,但无法显示实际效果(说好的红色按钮呢?)一脸懵逼!
除此之外,项目还包含了一些冗余的代码,并且助手里有些描述也有问题(过时了)。例如:
keys() returns a list of style names that this plugin can create, while create() takes such a string and returns the QStyle corresponding to the key. Both functions are pure virtual functions reimplemented from QStylePlugin.
查看 QStylePlugin
文档:
...
class Q_WIDGETS_EXPORT QStylePlugin : public QObject
{
Q_OBJECT
public:
explicit QStylePlugin(QObject *parent = Q_NULLPTR);
~QStylePlugin();
virtual QStyle *create(const QString &key) = 0;
};
...
What?纯虚函数 keys()
呢?。。。如果没记错的话,在 Qt 4.8 版本是有这个纯虚函数的,但是 5.x 已经去掉了。
所以,尽信书不如无书!即使是助手等一些官方教程也有过时的时候。。。遇到问题不要心存侥幸,抱着似是而非的心态,有疑惑一定要搞明白!
好吧,那就以此为例,顺便解决所有遇到的问题。
一个简单的样式插件
编写样式插件,涉及以下步骤:
- 实现一个
QStyle
,为 GUI 提供样式和外观。 - 编写样式插件 - 子类化
QStylePlugin
:- 重新实现纯虚函数
create()
- 使用
Q_PLUGIN_METADATA()
宏导出该类
- 重新实现纯虚函数
- 使用合适的
.pro
文件构建插件
在插件创建完成之后,使用以下方式加载:
- 使用
QStyleFactory::create()
创建并返回一个 QStyle 对象 - 使用
QApplication::setStyle()
设置程序的样式 - 样式插件必须被放置在
styles
目录中,该目录与可执行程序处于同一位置。
下面,来实现一个带有蓝色文本的按钮样式插件,效果如下:
样式插件
工程文件 -
.pro
由于我们正在构建的是一个共享库,而不是可执行文件。所以在 .pro
中,需要将 TEMPLATE
设置为 lib
,同时还必须将 CONFIG
设置为 plugin
。
plugin.pro
内容如下:
QT += widgets
TEMPLATE = lib
CONFIG += plugin
TARGET = stylePlugin
HEADERS += \
simple_style.h \
style_plugin.h
OTHER_FILES += simple_style.json
win32 {
CONFIG(debug, release|debug):DESTDIR = ../debug/styles/
CONFIG(release, release|debug):DESTDIR = ../release/styles/
} else {
DESTDIR = ../styles/
}
注意: 根据 QStylePlugin
的要求,插件需要被存储在 styles
文件夹中,因为这是 Qt 搜索样式插件的路径。
自定义样式 - QStyle
QProxyStyle
是一个很方便的类,包装了一个 QStyle
,用于动态覆盖特定的样式行为。所以,自定义的样式可以用它来实现。
simple_style.h
内容如下:
#ifndef SIMPLE_STYLE_H
#define SIMPLE_STYLE_H
#include <QProxyStyle>
class SimpleStyle : public QProxyStyle
{
Q_OBJECT
public:
SimpleStyle() {}
void polish(QPalette &palette) override
{
palette.setBrush(QPalette::ButtonText, Qt::blue);
}
};
#endif // SIMPLE_STYLE_H
插件类 -
StylePlugin
StylePlugin
继承了 QStylePlugin
,是插件类。
style_plugin.h
内容如下:
#ifndef STYLE_PLUGIN_H
#define STYLE_PLUGIN_H
#include <QStylePlugin>
#include "simple_style.h"
class StylePlugin : public QStylePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "simple_style.json")
public:
StylePlugin() {}
QStyle *create(const QString &key) override
{
if (key.toLower() == "simplestyle")
return new SimpleStyle();
return Q_NULLPTR;
}
};
#endif // STYLE_PLUGIN_H
create()
用于创建并返回给定样式 key
的 QStyle
对象,如果插件无法创建样式,则应该返回 Q_NULLPTR
。
注意: 样式 key
通常是所需样式的类名,这些 key 不区分大小写。区分大小写因插件而异,所以在实现新插件时需要检查。
插件的元数据 - Json 文件
Json 元数据文件 simple_style.json
需要包含插件支持的样式名称:
{
"Keys": [ "simplestyle" ]
}
注意: 这个文件非常关键,在插件生成之后,可以通过 QStyleFactory::keys()
来检测有效的 keys。也就是说,Json 文件中设置的值会由这个静态函数返回。
加载插件
一切准备就绪,来实现一个简单的应用程序,以动态加载插件。
工程文件 - .pro
由于这里需要的是一个可执行程序,所以需要将 TARGET 设置为 app。
app.pro
内容如下:
QT += widgets
SOURCES += main.cpp
TARGET = app
win32 {
debug:DESTDIR = ../debug/
release:DESTDIR = ../release/
} else {
DESTDIR = ../
}
main() 函数
当 QApplication
对象初始化完成后,使用 QStyleFactory::keys()
来检测所有有效的 keys,并使用 create()
(它是所有样式插件的包装器)来使用自定义的样式插件。
main.cpp
内容如下:
#include <QApplication>
#include <QPushButton>
#include <QStyleFactory>
#include <qDebug>
int main(int argv, char *args[])
{
QApplication app(argv, args);
// 设置样式
qDebug() << QStyleFactory::keys();
QApplication::setStyle(QStyleFactory::create("simplestyle"));
QPushButton button("Blue Button");
button.resize(300, 100);
button.show();
return app.exec();
}
有效的 keys:
(“simplestyle”, “Windows”, “WindowsXP”, “WindowsVista”, “Fusion”)
可以看出,simplestyle
已经被包含进去了!
源码地址
GitHub 源码地址:StylePlugin