qt style sheet(QSS)无效原因整理

Qt Style Sheet(以下简称QSS)是Qt基于CSS2提供的一种快速调整程序界面的方法。但在实际使用过程中,经常会遇到设置QSS无效的情况。本文列举了几种比较常见的原因。

继承于QWidget却未重写paintEvent(QPaintEvent *e)函数

在QSS的官方文档中对于QWidget的介绍如下

Supports only the background, background-clip and background-origin properties.
If you subclass from QWidget, you need to provide a paintEvent for your custom QWidget as below:

1
2
3
4
5
6
7
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

The above code is a no-operation if there is no stylesheet set.

也就是说,对于一个QWidget,它仅仅支持设置背景色的QSS,如果一个继承于QWidget的子类想要支持其他的QSS,就需要像上面那样重新实现paintEvent函数。这是绝大部分人设置QSS无效的主要原因,StackOverflow上有不少类似的问题。

未正确添加Q_OBJECT

由于QSS是通过Qt的元对象系统(The Meta-Object System)支持,因而需要在头文件中private块中添加Q_OBJECT宏。

QSS生效但被子控件遮挡

这一种情况在对容器类空间,如QWidgetQFrame等,对于这类控件设置QSS时尤其得注意QSS效果是否会被子部件遮挡。如下面这个例子

1
2
3
4
5
6
7
8
9
Widget::Widget(QWidget *parent)
: QFrame(parent)
{
this->resize(100, 100);
this->setWindowFlags(Qt::FramelessWindowHint);
this->setStyleSheet("background: #FFFFFF; border-left: 3px solid gray;");
btn_ = new QPushButton(this);
btn_->resize(this->size());
}

这段QSS的作用是添加一个灰色左边框,然而由于btn_被调整为和Widget一样尺寸,导致左边框被按钮遮挡,效果图如下:

左边框被遮挡

对于这种情况,有两种解决方法,

  • 将子控件进行移动至不遮挡父组件的位置
    在上述函数体内最后添加btn_->move(3, 0);
  • 将子控件设为背景透明
    在上述函数体内最后添加btn->setFlat(true);

设置后效果如下

左边框可见

  1. 对于QPushButton等控件设置透明的方式是将其设为扁平;
  2. 图中右边和下方深色是按钮的边框。

QSS属性顺序有误

QSS的每条属性并非是毫不相关的,很多时候某个属性的设置依赖于另一个属性的设置。

继续以上面的QSS为例,若将background: #FFFFFF;这条设置背景色的属性去除,后面设置边框的QSS是不会生效的。同样的,边框的宽度、样式和颜色顺序(对应于3px solid gray)必须固定,一旦颠倒三条中任意两条或缺少某一条,边框的QSS设置变不会生效。这一点尤其需要注意,具体的顺序可以多参考官方的示例文档。

总结

以上是个人遇到的几种QSS设置后无效的情况总结,实际使用中很可能还会遇到很多其他的情况导致QSS无效。QSS目前作为Qt对控件进行修饰的一种途径,具有十分灵活的特性。但QSS仍有较多的坑需要在使用中去慢慢摸索。