Qt给一个形状添加外发光的效果

发布时间 2023-07-06 11:26:01作者: 兜尼完

我们知道给控件添加特效可以使用QGraphicsEffect类。但是如果不针对整个控件而只是针对控件内的某个元素怎么添加外发光效果呢?比如说我在控件内绘制一个六边形,要给这个六边形添加外发光效果。一般的做法是先对六边形模糊一下,然后先绘制模糊的六边形再在其上叠加绘制原始六边形。绘制多边形QPainter类有这个功能。因此主要问题就是实现模糊效果,对此Qt是没有直接提供这个功能的,想实现这个功能需要自己写。解决方案可以有:

  1. 自己实现一个模糊函数,或借助图像处理库实现模糊函数。
  2. Qt中有一个名为qt_blurImage(...)的函数可以模糊图片,但是它没有对开发者公开。有兴趣的可以搜一下这个函数。
  3. QGraphicsItem也可以添加QGraphicsEffect特效。所以可以用Qt的QGraphicsScene的render(...)函数将其中添加了模糊特效的QGraphicsItem转成QPixmap,然后作为位图绘制。注意这里不能直接用QGraphicsItem的paint函数输出位图,因为paint函数输出不了特效。

既然使用了Qt,那就尽量全用Qt实现。所以本文主要讨论第3种方法。用QGraphicsScene实现形状模糊化。模糊函数如下。以下代码的开发环境是VS2017和Qt5.9:

const QPointF MOscil::markerPoly[] = /* 一个箭头 */
{
    QPointF(3.464101, 2.0), QPointF(2.338268, 2.65),
    QPointF(3.338268, 4.382051), QPointF(2.125833, 5.082051),
    QPointF(1.125833, 3.35), QPointF(0, 4.0),
    QPointF(0, 0), 
};

...

void MOscil::obtainBlurPoly(qreal radius, QPixmap& map)
{
    QPixmap map1(32, 32);
    map1.fill(Qt::transparent);
    QPainter painter1(&map1);
    painter1.setPen(Qt::NoPen);
    painter1.setBrush(Qt::blue);
    painter1.translate(4, 4); /* 注意这里偏移4像素,留白 */
    painter1.scale(4, 4);
    painter1.drawPolygon(markerPoly, 7);

    QPixmap map2(32, 32);
    map2.fill(Qt::transparent);
    QPainter painter2(&map2);
    QGraphicsPixmapItem *pxItem = new QGraphicsPixmapItem;
    pxItem->setPixmap(map1);
    QGraphicsBlurEffect* blur = new QGraphicsBlurEffect;
    blur->setBlurRadius(radius);
    pxItem->setGraphicsEffect(blur);
    QGraphicsScene scene;
    scene.addItem(pxItem);
    scene.render(&painter2);
    map = std::move(map2);
}

上述代码中的MOscil类是我自定义的一个用于显示波形图的类。它来自我的博文“”但有较大改动。其中markerPoly数组表示的是一个大约6×6的箭头,在绘制中我们把它放大了4倍并且居中放置。用32×32的位图装它完全装得下。下面是显示效果截图:

上图是黄色箭头,蓝色外发光。基本方法就是这样。