Qt QWidget 独立窗口抗锯齿圆角的一个实现方案(支持子控件) 您所在的位置:网站首页 qwidget设置模态不起作用 Qt QWidget 独立窗口抗锯齿圆角的一个实现方案(支持子控件)

Qt QWidget 独立窗口抗锯齿圆角的一个实现方案(支持子控件)

2023-09-30 21:48| 来源: 网络整理| 查看: 265

QWidget独立窗口抗锯齿圆角窗口的一个实现方案

由于 QWidget::setMask 接口设置圆角不支持抗锯齿,所以通常会使用透明窗口加圆角背景,但圆角背景不能满足对子控件的裁剪,子控件与圆角区域重叠的部分还是能显示出来。当然对于大多数窗口,留出足够的边距也是可以接受。

对一些特殊场景,比如QComboBox的列表框,UI设计师强烈要求圆角,列表与它的容器不能有边距,常规办法就很难做到。笔者在经过长时间的研究,有了一个可能的方案。

最终实现效果如下图,可以看到,列表项区域,滚动条区域也能够正常显示圆角。 抗锯齿圆角

注意,该方案可能不适用一些场景:

特殊的平台或Qt配置复杂窗口且有性能要求窗口尺寸较大(可以优化)有嵌入式窗口、OpenGL、QWindow等 方案 基本原理

Qt的每个独立窗口,默认都是在一张图片上,层叠绘制所有子控件。通常我们自绘控件时,几乎不会使用QPainter::setCompositionMode设置其他混合模式,会出现比较奇怪的效果。但如果使用透明背景窗口,使用混合模式其实跟在QPixmap或QImage上绘制一样。

另外一点,当一个控件重绘时,由于底层的绘制会影响到上层透明合成,所以Qt会从下到上按顺序绘各个控件的脏区域。

所以理论上,如果在一个窗口上增加一个全尺寸的遮罩,重绘时使用混合模式就可以实现对一些像素的清除,且支持抗锯齿。

代码步骤

创建一个QWidget作为遮罩

遮罩置于顶层,鼠标设置透传(WA_TransparentForMouseEvents)

遮罩跟随窗口尺寸大小同步变化,保持一致。安装事件过滤器即可(installEventFilter)

重写paintEvent,利用混合模式清除圆角像素

以下绘制逻辑比较直接,建议优化

//创建一个图片,填充透明色 QPixmap pix(this->size()); pix.fill(QColor(0,0,0,0)); // 在改图片上填充一个圆角区域,需要设置抗锯齿 QPainter painter(&pix); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; //这里圆角区域需要根据dpi、size调整 path.addRoundedRect(QRectF(pix.rect()).adjusted(0.5, 0.5, -0.5, -0.5), 10, 10); painter.fillPath(path, Qt::white); painter.end(); // 在窗口上绘制该圆角图片 painter.begin(this); painter.setRenderHint(QPainter::Antialiasing); // 该混合模式会根据source像素的透明度,调整目标的透明度 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); painter.drawPixmap(0, 0, pix); // 恢复默认混合模式,绘制边框,如果没有则不用 painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.setPen(QPen(QColor(0xCA64EA), 1.0)); painter.drawPath(path); 优化方向

性能优化

上面的示例,使用了一整张图片对窗口像素进行混合模式的运算,且每次子控件重绘都会引起遮罩的重绘,性能比较差。可以考虑仅在四周设置圆角的遮罩。

圆角绘制优化

本文使用了一个不透明的圆角区域对窗口设置裁剪,圆角的参数是固定在代码里的。实际QSS是可以设置窗口的圆角,因此可以借助QSS来生成一张圆角图片,就避免代码里包含固定数值。

具体实现原理可以参考之前的文章,这里不具体展示了: QComboBox文字居中的一种解决办法 Qt实现一个支持QSS的Switch Button Qt借助隐藏控件和QSS绘制重复元素



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有