Qt图形特效:QGraphicsEffect

本文介绍了Qt中的QGraphicsEffect类,展示了如何创建和使用自定义图形效果,如GlowEffect的发光效果实例,以及如何处理源变化和边界调整。通过实例学习如何实现图形模糊、颜色调整和透明度等效果。

一、描述

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);

总效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值