【QT】Svg图标

SVG

一般而言,QSS是无法直接使用svg图像的。
那如何才能显示svg呢?我们知道svg的好处有很多,如矢量图,体积小等等
svg本来就是一个document(可参考12),QT提供了QSvgRenderer用于访问svg doc

QT绘制SVG流程

  1. QSvgRenderer读取svg内容
  2. 创建QPixmap用于容纳svg图像
  3. 使用QPainter绘制svg

PS: 注意QPixmap设置宽高时需要考虑到DPI,否则会造成图像错位
对于一些控件QLabel来说,设置setScaledContents(true)、adjustSize()、setSizePolicy(Preferred)进行缩放

e.g.

// .h
#ifndef __UISVGICON_H__
#define __UISVGICON_H__

#include "UICommon_Global.h"

class QString;
class QPixmap;

class UP3DUICOMMON_EXPOT UISvgIcon
{
public:
	explicit UISvgIcon(const QString& svgPath);
	~UISvgIcon();

public:
	/// @brief 获取SVG图像
	const QPixmap& pixmap();

	/// @brief 填充色属性修改
	void setFill(const QString &targetName, const QString &color);

private:
	class Pimpl;
	std::unique_ptr<Pimpl> impl_;
};

#endif // !__UISVGICON_H__
#include "UISvgIcon.h"

#include <UPGL/UPGLUtil.h>

#include <QtCore/QFile>
#include <QtCore/QPointer>

#include <QtGui/QPixmap>
#include <QtGui/QPainter>
#include <QtGui/QScreen>

#include <QtSvg/QSvgRenderer>

#include <QtXml/QDomDocument>

class UISvgIcon::Pimpl
{
public:
	Pimpl(const QString &svgPath);
	~Pimpl();

public:
	void setSVGProperty(QDomElement &&elem, const QString &tagName, const QString &property, const QString &value);
	QString SVGProperty(QDomElement &&elem, const QString &tagName, const QString &property);

public:
	QScopedPointer<QDomDocument> mSvgDoc_;
	QScopedPointer<QSvgRenderer> pSvgRender_;
	QScopedPointer<QPixmap> pPixmap_;

	QPixmap mEmptyMap_;

	QString mSvgPath_ = "";
};

UISvgIcon::Pimpl::Pimpl(const QString &svgPath)
{
	mSvgPath_ = svgPath;

	mSvgDoc_.reset(new QDomDocument());
	QFile tFile(mSvgPath_);
	tFile.open(QIODevice::ReadOnly | QFile::Text);
	mSvgDoc_->setContent(&tFile);
	tFile.close();

	pSvgRender_.reset(new QSvgRenderer(mSvgDoc_->toByteArray()));

	auto tDpi = UPGLUtil::getScreen()->logicalDotsPerInch();

	pPixmap_.reset(new QPixmap(SVGProperty(mSvgDoc_->documentElement(), "svg", "width").toInt() * tDpi,
	                           SVGProperty(mSvgDoc_->documentElement(), "svg", "height").toInt() * tDpi));

	pPixmap_->fill(Qt::transparent);
	QPainter tPainter(pPixmap_.get());
	pSvgRender_->render(&tPainter);
}

UISvgIcon::Pimpl::~Pimpl()
{
}

void UISvgIcon::Pimpl::setSVGProperty(QDomElement &&elem, const QString &tagName, const QString &property, const QString &value)
{
	if (elem.tagName().compare(tagName) == 0)
	{
		elem.setAttribute(property, value);
	}

	for (int i = 0; i < elem.childNodes().count(); i++)
	{
		if (elem.childNodes().at(i).isElement())
		{
			setSVGProperty(elem.childNodes().at(i).toElement(), tagName, property, value);
		}
	}
}

QString UISvgIcon::Pimpl::SVGProperty(QDomElement &&elem, const QString &tagName, const QString &property)
{
	if (elem.tagName().compare(tagName) == 0)
	{
		return elem.attribute(property);
	}

	QString tPropertyStr;
	for (int i = 0; i < elem.childNodes().count(); i++)
	{
		if (elem.childNodes().at(i).isElement())
		{
			tPropertyStr = SVGProperty(elem.childNodes().at(i).toElement(), tagName, property);
			if (!tPropertyStr.isEmpty())
			{
				return tPropertyStr;
			}
		}
	}

	return tPropertyStr;
}

UISvgIcon::UISvgIcon(const QString &svgPath)
    : impl_(std::make_unique<Pimpl>(svgPath))
{
}

UISvgIcon::~UISvgIcon()
{
}

const QPixmap& UISvgIcon::pixmap()
{
	if (!impl_->pPixmap_.isNull())
	{
		return *impl_->pPixmap_;
	}

	// NOTE 禁止返回临时变量的引用
	return impl_->mEmptyMap_;
}

void UISvgIcon::setFill(const QString &targetName, const QString &color)
{
	impl_->setSVGProperty(impl_->mSvgDoc_->documentElement(), targetName, "fill", color);

	QPainter tPainter(impl_->pPixmap_.get());
	impl_->pSvgRender_->load(impl_->mSvgDoc_->toByteArray());
	impl_->pSvgRender_->render(&tPainter);
}

使用

QScopedPointer<UISvgIcon> pInfoSvg_;

pInfoSvg_.reset(new UISvgIcon(":/Resource/skins/default/app/IconWarn.svg"));
QToolButton* closeButton = new QToolButton;
closeButton->setIcon(*closeIcon->pixmap());

  1. SVG基本图形绘制教程 ↩︎

  2. SVG 教程 ↩︎

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值