Qt滚动条(QScrollBar)圆角样式问题跟踪

Qt使用样式表设置圆角滚动条的黑色背景问题

今天在知乎上看到一篇文章,描述使用样式表设置圆角滚动条时,圆角四周会有黑色区域而非透明,文章里最后借用 QSlider 来实现圆角滚动条。

我好奇 Qt 居然会出现这样的Bug,就研究了一下,顺便做个记录。


设置圆角样式:

QScrollBar 有一些子控件区域,handle 为滑块, add-line、sub-line 默认是滚动条两侧箭头区域,add-page、sub-page 是滑块两侧区域,使用以下样式表设置圆角,除了滑块与主背景,都设置为透明:

QScrollBar:horizontal{
    
    
    background: #309AB8;
    border-radius: 15px;
    min-height: 30px;
    max-height: 30px;
}
QScrollBar::handle:horizontal{
    
    
    background: #FFFFFF;
    border-radius: 15px;
    min-width: 30px;
}
QScrollBar::add-page,
QScrollBar::sub-page{
    
    
    background: transparent;
}
QScrollBar::add-line,
QScrollBar::sub-line{
    
    
    background: transparent;
}

结果如下图所示,确实周围出现黑色像素:
圆角样式


原因跟踪:

一开始尝试调整子控件的样式,无解,而且圆角四周会出现奇怪的刷新问题。

重写 QScrollBar::paintEvent,使用老方法自绘。发现即使不绘制子控件,也是会有黑色像素,调试源码猜测是绘制边框的问题。

在样式表里设置一下 “border: 1px solid transparent”,黑色像素居然没有了,只不过边框歪歪扭扭对不齐。

调试源码又看不明白源码是怎么绘制边框的,便在 paintEvent 什么都不做,发现整个滚动条区域居然都是黑色的:
黑色
这种情况在 Qt 中并不多见,经常自绘或者写无边框窗口总会遇到,无非是几个特定属性,查看 QScrollBar 源码的构造函数发现:
在这里插入图片描述
尝试手动关闭该属性,黑色背景消失。


解决方案:

所以,根本原因在 Qt::WA_OpaquePaintEvent 被默认开启了,关闭掉就行了。测试过程中发现设置 “border-style: solid;”也可以解决,可以根据情况实际自己选择。

原理分析:

到此已经解决了问题,不过有两个问题还需要再回答。

  1. Qt::WA_OpaquePaintEvent 代表什么意思?
    文档里解释,该属性指示窗口在收到重绘事件时会绘制整个区域,可以避免重绘前频繁擦除背景,在不支持双缓冲技术的系统上减少闪烁之类的。而黑色实际是Windows窗口管理系统上的空颜色。
    所以开启该属性后,因为样式的圆角,圆角外的区域没有按规则绘制有效像素,所以就是黑色的。
  2. 设置 border-style 能解决的原因是什么?
    因为该样式会关闭 Qt::WA_OpaquePaintEvent 属性,可以通过 QWidget::testAttribute 验证。
    在Qt的源码里,QStyleSheetStyle::polish 也有对应的逻辑:
    源码
    判断比较多,该例子中在 rule.boder()->isOpaque() 里面有对 border 样式判断,solid 样式恰好返回了 false,如果没有设置则是 none,可能返回true,具体其他情况就没有详细研究。

猜你喜欢

转载自blog.csdn.net/eiilpux17/article/details/116502351
今日推荐