一、描述
1、QGraphicsEffect类是所有图形效果的基类。
2、效果通过挂接到渲染管道并在源(例如QGraphicsPixmapItem、QWidget)和目标设备(例如QGraphicsView的视口)之间进行操作来更改元素的外观。
Qt提供以下图形效果:
- QGraphicsBlurEffect:模糊
- QGraphicsDropShadowEffect:阴影
- QGraphicsColorizeEffect:颜色
- QGraphicsOpacityEffect:透明度
3、若要创建自定义效果,请创建QGraphicsEffect的子类(或任何其他现有的效果),然后重新实现虚函数draw()。每当需要重绘效果时,都会调用此函数。在draw()函数中,可以调用sourcePixmap()来获取图形效果源的像素图,然后可以对其进行处理。
4、如果效果改变,请使用update()重绘。如果自定义效果更改了源的边界矩形,例如径向发光效果可能需要应用额外的边距,则可以重新实现虚拟的boundingRectFor()函数,并在此矩形发生变化时调用updateBoundingRect()来通知框架。调用sourceChanged()函数以通知效果该源已以某种方式更改。
二、类型成员
1、QGraphicsEffect::ChangeFlag,该枚举描述了QGraphicsEffectSource中发生的变化。
- SourceAttached:图形特效已安装在源上。
- SourceDetached:图形特效已从源上卸载。
- SourceBoundingRectChanged:源的边界矩形已更改。
- SourceInvalidated:源的外观已更改。
2、QGraphicsEffect::PixmapPadMode,该枚举描述了应如何填充从sourcePixmap()返回的像素图。
- NoPad:像素图不应接收任何其他填充。
- PadToTransparentBorder:应填充像素图,以确保其具有完全透明的边框。
- PadToEffectiveBoundingRect:应填充像素图以匹配图形特效的有效边界矩形。
三、属性
1、enabled : bool
此属性保存是否启用效果。如果禁用了效果,则将正常渲染源,而不会受到效果的干扰。 如果启用了效果,则将在应用效果的情况下渲染源。默认情况下启用此属性。使用此属性,可以在慢速平台上禁用某些效果,以确保用户界面具有响应性。
四、成员函数
1、void update()
图形特效的重绘。 需要重绘效果时调用此函数。 此功能不会触发源的重绘。
2、QRectF boundingRect()
返回此图形特效的有效边界矩形,即源在设备坐标中的边界矩形。
3、[virtual] QRectF boundingRectFor(const QRectF &rect)
参数是目标设备坐标中的矩形,返回此图形特效的有效边界矩形。在编写自定义效果时,每当更改任何可能导致此函数返回不同值的参数时,都必须调用updateBondingRect()。
4、void draw(QPainter *painter)
这个纯虚函数绘制效果,并在需要绘制源代码时调用。在QGraphicsEffect子类中重新实现此函数,以使用painter提供效果的绘图实现。此函数不应由用户显式调用。
5、void drawSource(QPainter *painter)
使用给定的QPainter直接绘制源。此函数只能从QGraphicsEffect::draw()调用。
6、QRectF sourceBoundingRect(Qt::CoordinateSystem system = Qt::LogicalCoordinates)
返回映射到给定系统的源的边界矩形。在draw()之外以Qt::DeviceCoordinates调用此函数将产生未定义的结果,因为没有可用的设备上下文。
Qt::CoordinateSystem:该枚举指定坐标系。
- Qt::DeviceCoordinates:坐标相对于对象绘画设备的左上角。
- Qt::LogicalCoordinates:坐标相对于对象的左上角。
7、void sourceChanged(QGraphicsEffect::ChangeFlags flags)
通知图形特效源已更改。如果图形特效应用了任何高速缓存,则必须清除此高速缓存以反映源的新外观。
8、bool sourceIsPixmap()
如果源实际上是一个像素图(例如QGraphicsPixmapItem),则返回true。此功能对于优化目的很有用。 例如,如果此函数返回true,则在设备坐标中绘制源来避免像素图缩放毫无意义-无论如何,源像素图都会缩放。
9、QPixmap sourcePixmap(Qt::CoordinateSystem system = Qt::LogicalCoordinates, QPoint *offset = nullptr, QGraphicsEffect::PixmapPadMode mode = PadToEffectiveBoundingRect)
返回其中绘制了源的像素图。系统指定要用于源的坐标系。可选的offset参数返回应使用当前绘制器在其上绘制像素图的偏移量。要控制如何填充像素图,请使用mode参数。
10、void QGraphicsEffect::updateBoundingRect()
当效果的边界矩形已更改时,此函数会通知效果框架。作为自定义效果作者,只要更改任何会使虚boundingRectFor()函数返回不同值的参数,就必须调用此函数。如果需要,此函数将调用update()。
五、一个自定义发光图形特效的实例
代码来自:GlowEffect——发光效果的QGraphicsEffect,做了一些修改。
#ifndef GLOWEFFECT_H
#define GLOWEFFECT_H
#include <QGraphicsEffect>
//声明将使用qt内部的模糊图像函数
extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
class GlowEffect : public QGraphicsEffect
{
Q_OBJECT
public:
explicit GlowEffect(QObject *parent = nullptr);
private:
int radius;
QColor color;//发光颜色
protected:
void draw(QPainter *painter)override;
void sourceChanged(ChangeFlags flags)override;
QRectF boundingRectFor(const QRectF &sourceRect) const override;
};
#endif // GLOWEFFECT_H
#include "gloweffect.h"
#include <qpainter.h>
#include <QPixmap>
#include <QDebug>
GlowEffect::GlowEffect(QObject *parent) :
QGraphicsEffect(parent), radius(0), color(255, 255, 255, 255)
{
radius = 15;
color = Qt::red;
}
QRectF GlowEffect::boundingRectFor(const QRectF &sourceRect) const
{
QRectF tmp(sourceRect);
tmp.setBottomRight(tmp.bottomRight() + QPointF(radius * 2, radius * 2));
return tmp;
}
void GlowEffect::sourceChanged(ChangeFlags flags)
{
updateBoundingRect();
update();
}
void GlowEffect::draw(QPainter *painter)
{
if (radius == 0)
{
drawSource(painter);
return;
}
QPixmap source = sourcePixmap();
QImage sourceBlured(source.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied);
sourceBlured.fill(Qt::transparent);
QPainter tmpPainter;
tmpPainter.begin(&sourceBlured);
tmpPainter.drawPixmap(radius, radius, source);
tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
tmpPainter.fillRect(sourceBlured.rect(), color);
tmpPainter.end();
qt_blurImage(sourceBlured, radius, true);
sourceBlured.save(QString("xx%1.png").arg(i));
++i;
for (int i = 0;i < 6;++i)
{
painter->drawImage(0, 0, sourceBlured);
}
painter->drawPixmap(radius, radius, source);
}
ui文件:
绘制代码分析
当绘制半径为0时,只绘制源,即不绘制图形特效
if (radius == 0)
{
drawSource(painter);
return;
}
获取源对象的像素图,保存此像素图查看如下:
QPixmap source = sourcePixmap();
注意尺寸,可见源图像的尺寸由boundingRectFor()函数确定:
QRectF GlowEffect::boundingRectFor(const QRectF &sourceRect) const
{
QRectF tmp(sourceRect);
tmp.setBottomRight(tmp.bottomRight() + QPointF(radius * 2, radius * 2));
return tmp;
}
创建一个比源对象的像素图宽高都大radius * 2的图像,填充透明色:
QImage sourceBlured(source.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied);
sourceBlured.fill(Qt::transparent);
在此图上绘制源对象像素图:
QPainter tmpPainter;
tmpPainter.begin(&sourceBlured);
tmpPainter.drawPixmap(radius, radius, source);
tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
tmpPainter.fillRect(sourceBlured.rect(), color);
tmpPainter.end();
绘制位置如图:
调用Qt内部的模糊图像函数进行模糊图像处理:
qt_blurImage(sourceBlured, radius, true);
在源上绘制此模糊图像:
painter->drawImage(0, 0, sourceBlured);
大概位置如下:
效果:
重复画几次效果:
for (int i = 0;i < 6;++i)
{
painter->drawImage(0, 0, sourceBlured);
}
加上源图像:
painter->drawPixmap(radius, radius, source);
总效果: