从内存中的 SVG 内容创建 QIcon
Creating QIcon from SVG contents in memory
我们如何在内存缓冲区中创建具有 SVG 图标内容的QIcon
对象?
附言最初想创建QSvgIconEngine,但它隐藏在插件层上,我无法明确创建它。如何从插件加载(考虑到该插件已加载)?
在这里和那里挖掘了一段时间,并深入研究了 QIcon 本身如何使用 svg 文件来加载图标,以下是我学到的:
-
QIcon
,当使用 svg 文件(或任何其他图像类型)调用时,它会随后调用addFile()
,它仅使用文件的扩展名(在 Qt 中称为QFileInfo::suffix
)来确定将图像文件转换为图标的方法。 -
该方法(语义上)由
QIconEngine
实例确定 -
每种图像类型的
QIconEngine
类显然不是我们(Qt开发人员)可以简单地访问的;显然有一个插件系统可以使用,并且在编译时不可用(至少不是简单地)。
另一方面;QIcon如何工作?当从 QIcon 请求图标时,它会使用传递给它的信息来确定要使用的引擎,并创建引擎的实例。然后,每次图标需要绘制一些东西时,它都会要求引擎绘制一个给定一定大小的图标。大小用于函数QIconEngine::pixmap()
,该函数创建具有所需大小的像素图,然后使用QIconEngine::paint()
方法在该像素图上绘制。
因此,鉴于这些信息,解决方案只是编写一个图标引擎,QIcon 将使用该引擎根据传递给它的大小生成图标。具体操作方法如下:
所以这是头文件 SvgIconEngine.h
#ifndef SVGICONENGINE_H
#define SVGICONENGINE_H
#include <QIconEngine>
#include <QSvgRenderer>
class SVGIconEngine : public QIconEngine {
QByteArray data;
public:
explicit SVGIconEngine(const std::string &iconBuffer);
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode,
QIcon::State state) override;
QIconEngine *clone() const override;
QPixmap pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state) override;
signals:
public slots:
};
#endif // SVGICONENGINE_H
这是实现,SvgIconEngine.cpp
#include "SvgIconEngine.h"
#include <QPainter>
SVGIconEngine::SVGIconEngine(const std::string &iconBuffer) {
data = QByteArray::fromStdString(iconBuffer);
}
void SVGIconEngine::paint(QPainter *painter, const QRect &rect,
QIcon::Mode mode, QIcon::State state) {
QSvgRenderer renderer(data);
renderer.render(painter, rect);
}
QIconEngine *SVGIconEngine::clone() const { return new SVGIconEngine(*this); }
QPixmap SVGIconEngine::pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state) {
// This function is necessary to create an EMPTY pixmap. It's called always
// before paint()
QImage img(size, QImage::Format_ARGB32);
img.fill(qRgba(0, 0, 0, 0));
QPixmap pix = QPixmap::fromImage(img, Qt::NoFormatConversion);
{
QPainter painter(&pix);
QRect r(QPoint(0.0, 0.0), size);
this->paint(&painter, r, mode, state);
}
return pix;
}
注意:你必须覆盖clone()
,因为它是一个抽象方法,你必须覆盖pixmap()
,因为没有它,你将没有一个空的像素图来绘制svg。
要使用它,只需执行以下操作:
std::string iconSvgData = GetTheSvgPlainData();
QIcon theIcon(new SVGIconEngine(iconSvgData));
//Use the icon!
请注意,QIcon 拥有引擎对象的所有权。当它被摧毁时,它会摧毁它。
玩得愉快!
我手头没有 c++,但应该很容易转换:
QtGui.QIcon(
QtGui.QPixmap.fromImage(
QtGui.QImage.fromData(
b'<svg version="1.1" viewBox="0 0 32 32"'
b' xmlns="http://www.w3.org/2000/svg">'
b'<circle cx="16" cy="16" r="4.54237"/></svg>')))
此代码将创建带有黑色圆圈的透明 32 x 32 像素图标。
我们如何
SVG
QIcon
在 内存缓冲区?
为此,所有必需的功能都通过QSvgRenderer类的外部接口提供。要构造这种类型的渲染器,我们需要使用以下任一:
QSvgRenderer(const QByteArray &contents, QObject *parent = Q_NULLPTR);
QSvgRenderer(QXmlStreamReader *contents, QObject *parent = Q_NULLPTR);
或者我们可以加载内容:
bool QSvgRenderer::load(const QByteArray &contents)
bool QSvgRenderer::load(QXmlStreamReader *contents)
并创建实际图标:
QIcon svg2Icon(const QByteArray& svgContent, QPainter::CompositionMode mode =
QPainter::CompositionMode_SourceOver)
{
return QIcon(util::svg2Pixmap(svgContent, QSize(128, 128), mode));
}
QPixmap svg2Pixmap(const QByteArray& svgContent,
const QSize& size,
QPainter::CompositionMode mode)
{
QSvgRenderer rr(svgContent);
QImage image(size.width(), size.height(), QImage::Format_ARGB32);
QPainter painter(&image);
painter.setCompositionMode(mode);
image.fill(Qt::transparent);
rr.render(&painter);
return QPixmap::fromImage(image);
}
我们也可以使用其他构图模式,例如,QPainter::RasterOp_NotSourceOrDestination
反转图标颜色。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 使用std::multimap迭代器创建std::list
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 使用CMake创建QML插件
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 试图在visual studio上用C++创建一个桌面应用程序
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 如何在C++20中创建模板别名的推导指南
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 链接到自行创建的dll失败
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++类内存结构中创建"spacer"?
- 从内存中的 SVG 内容创建 QIcon
- 如何从二进制数据创建 QIcon