Qt使用私有接口绘制窗口阴影

Qt使用私有接口绘制窗口阴影

该方法仅适用于矩形区域,异形区域可以参考

大多数软件UI设计都喜欢给控件增加阴影来制造分层效果,而比较好的阴影通常需要算法生成。在Qt中主要有两个方法来实现:

  1. QGraphicsDropShadowEffect
    该方法在指定QWidget下方生成阴影效果,可以设置颜色、偏移、阴影半径。该方法原理是先截取指定QWidget的渲染图像,对图像缩放、填充、模糊,绘制到下面的图层,效果很好。但有个非常大的缺点,由于需要考虑阴影图层的绘制,可能会影响整个窗口的渲染,一些状态不能及时刷新。而且,当阴影区域比较大时,效率非常低。

  2. 使用QSS样式表指定border-image
    该方法需要预先制作一张阴影图片,根据需要设置border-image的裁剪和伸缩区域。缺点是图片资源固定后不能再修改。

研究

经过对QGraphicsDropShadowEffect的源码分析,发现可以使用Qt未开放的接口来动态生成阴影。该接口定义在qpixmapfilter.cpp中,可以通过下面方式声明并使用:

QT_BEGIN_NAMESPACE
extern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
QT_END_NAMESPACE

这里提供一个测试代码,可以参考如何使用。

由于该接口仍然是对图像模糊处理,所以比较大的区域仍然有效率上的问题。Qt针对样式表绘制border-image提供了一个接口,可以分区域裁剪或伸缩绘制一张图片:

void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)

所以原理上可以先生成一张小一点的完整矩形阴影图片,然后通过该接口的QMargins参数设置图片的裁剪区域,就可以绘制任意矩形阴影,或者只要能分割成九宫格区域的阴影都可以。

具体方法就是,先参考测试代码生成一张阴影图片,再调用qDrawBorderPixmap绘制。经过测试,效率提升非常明显。

问题

qDrawBorderPixmap在高分辨率窗口上绘制是简单对图片各区域进行平滑缩放,所以图片设置devicePixelRatio没有用,所以生成阴影图片时只生成x1的图片即可,看起来没有明显差异。qDrawBorderPixmap内部使用的是QPainter::drawPixmapFragments绘制各区域图片,如果对该缺点比较在意,可以自己裁剪

你可能感兴趣的:(Qt,Qt技术总结,Qt,阴影,qss)