前言

  我们平时做的项目,应用程序界面非常美观,看起来十分炫酷,它是怎么实现的呢?本篇简单介绍QSS的使用,想要搞清楚原理,可以参考二狗大佬的博客。
  QSS用于修改界面外观,如果通过QSS文件的方式加载,直接修改QSS文件就能看到效果变化,不需要编译。QSS与CSS十分相似。

一、基本语法

  以QLabel为例,QSS实现如下:

QLabel {
    /* 相当于 font: bold 50px "Snell Roundhand"; */
    font-size: 50px;
    font-weight: bold;
    font-family: "Snell Roundhand";

    /* 文本的颜色 */
    color: white;

    /* 相当于 background: lightgray url(:/resources/horizontal-add-line.png); */

    background-color: lightgray;
    background-image: url(:/resources/horizontal-add-line.png);

    /* 还能使用渐变 */
    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                      stop: 0 #FFFFFF, stop: 1 #BB000000);

    /* 相当于 border: 5px solid gray; */
    border-width: 5px;
    border-color: gray;
    border-style: solid;

    /* 边框圆角 */
    border-radius: 10px;

    padding: 5px;
    margin: 10px;
}

1、字体

使用font设置字体。font的语法如下:

font: [font-style] [font-variant] [font-weight] [font-size] [font-family]

/* 按顺序设置,可以忽略其中某些值,例如:*/
font: italic bold 12px arial, sans-serif;

如果字体名字有空格则用双引号引起来,多个字体名字间用逗号分隔,如果第一个字体找不到则用第二个,依此类推。

2、文本颜色

使用color设置文本颜色。可以直接写颜色,如:white;可以写rgb颜色数值,如:rgb(2,2,2) ;也可以写16进制颜色信息,如:#00FF00

3、背景

使用background设置背景,可以设置如下属性:

  • background-color
  • background-position
  • background-repeat
  • background-origin
  • background-clip
  • background-attachment
  • background-image
    比如:
background: lightgray url(:/resources/horizontal-add-line.png);

其中url的路径,可以是资源文件路径(:/开头)、绝对路径和相对路径。
background-repeat,用于设置重复,可选值如下:

  • repeat-x:水平方向重复
  • repeat-y:垂直方向重复
  • no-repeat:不重复
    background-position,用于设置选取的素材位置,可选值如下:

  • top left

  • top center
  • top right
  • center left
  • center center
  • center right
  • bottom left
  • bottom center
  • bottom right
    background-attachment,用于设置跟随滚动条滚动,可选值如下:

  • scroll:背景随滚动条滚动

  • fixed:背景不随滚动条滚动
    background-color用于设置背景颜色,可以直接写入颜色,也支持渐变,渐变可选值如下:

  • qlineargradient 线性渐变

  • qradialgradient 辐射渐变
  • qconicalgradient 角度渐变
    比如:
/*
x1: 0, y1: 0,渐变的开始位置,为 border rectangle 的左上角(请参考盒子模型)
x2: 0, y2: 1,渐变的开始位置,为 border rectangle 的左下角
stop: 0.1 #FF0000,在 0.0 处渐变的颜色为 #FF0000
stop: 0.6 #00FF00,在 0.6 处渐变的颜色为 #00FF00
stop: 1.0 #0000FF,在 1.0 处渐变的颜色为 #0000FF
*/
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                        stop: 0.1 #FF0000,
                        stop: 0.6 #00FF00,
                        stop: 1.0 #0000FF);

渐变的坐标不是用具体像素表示,而是把渐变的坐标最小值定义为0,最大值定义为1,称为Normalization。其实,就是用比例表示,开始处用0表示,结束处用1表示,按比例计算实际的像素坐标。这样,就不需要关心像素坐标范围的具体值,不会因widget大小变化而变化。

除了使用background-image外,border-image也可以用于设置背景,区别在于,背景图和控件一样大时使用background-image,当不一样大时使用border-image。设置border-image,就一定要同时设置 border-width。用法如下:

border-width: 12px 12px 12px 12px;
border-image: url(:/img/round-button.png) 12 12 12 12 repeat stretch;

参数分别为:
背景图路径
背景图中最上面12px高的图像填充到widget的border-top
背景图中最右边12px宽的图像填充到widget的border-right
背景图中最下边12px高的图像填充到widget的border-bottom
背景图中最左边12px宽的图像填充到widget的border-left
水平方向的填充
垂直方向的填充。

后两个参数,可选值为:

  • stretch:用拉伸的方式来填充边框背景图
  • repeat:用平铺的方式填充边框背景图,当图片超过边界时则截断
  • round:用平铺的方式填充边框背景图,图片会根据边框尺寸动态调整图片大小直至正好可以铺满整个边框

    4、边框

    使用border设置边框,用法如下:
border: border-width border-style border-color

border-style,边框风格,可选值如下:

  • solid 实线边框
  • dotted 点状边框
  • none 无边框
  • dashed 虚线
  • double 双线
  • groove 3D凹槽边框
  • ridge 3D垄状边框
  • inset 上光源3D
  • outset 下光源3D
    使用border-radius设置边框圆角,但是如果给定的半径大于对应边的一半,圆角就没有效果了,在 CSS 里没有这个问题。

遗憾的是,QSS不支持阴影。

5、文本居中、对齐

widget及其子类中使用宏Q_PROPERTY 定义的 WRITE 函数可以在 QSS 中访问,我们可以通过这种方式实现某些效果,比如:

  • 设置文本居中:qproperty-alignment: AlignCenter,此外text-align不支持QLabel
  • 设置文本:qproperty-text: ‘It is amazing’
  • 设置对齐方式:
qproperty-alignment: 'AlignCenter'
qproperty-alignment: 'AlignBottom | AlignRight'

可以使用该方式实现很多效果,但qproperty-xxx 也不是万能的,在 :hover,:pressed 等伪类选择器中不生效。

二、加载QSS

1、widget对象调用setStyleSheet() 函数

QSS作用域是widget自己和它的所有子widget,如下:

QFrame *topFrame = new QFrame();
topFrame->setFrameShape(QFrame::StyledPanel);
topFrame->setFrameShadow(QFrame::Raised);
QPushButton *topButton = new QPushButton("Top Button");
QVBoxLayout *topLayout = new QVBoxLayout();
topLayout->addWidget(topButton);
topFrame->setLayout(topLayout);

QString qss = "QFrame {"
                  "    background: #AAA;"
                  "    border: 2px dashed gray;"
                  "}"
                  "QPushButton {"
                  "    font-size: 20px;"
                  "    padding: 5px 20px;"
                  "    color: black;"
                  "    border: 4px solid gray;"
                  "    background-color: rgb(230, 250, 250);"
                  "}";

 // 加载 QSS
 topFrame->setStyleSheet(qss);

2、QApplication 的对象调用setStyleSheet() 函数

QSS作用域是整个程序里面的所有widget,如下:

QApplication app(argc, argv);
app.setStyleSheet(qss)

3、Qt Designer中的Change styleSheet…

QSS作用域是widget自己和它的所有子widget,与方式1相同,只是不需要自己编写具体代码,打开ui文件生成的代码,可以看到里面也是调用的setStyleSheet() 函数。

4、从文件中加载

如果在代码或设计师里面设置QSS,则每次修改,都需要重新编译,才能生效。所以,实际项目中,QSS的设置一般都写在文件中,代码中只调用setStyleSheet()函数。

void DlgFirst::loadUI()
{
    QString filename = QString("%1/TmUI/First/dlgfirst.css").arg(g_strExeRoot);

    QFile fileSkin(filename);
    if(fileSkin.open(QIODevice::ReadOnly))
    {
        QString strSkin = QString::fromUtf8(fileSkin.readAll());
        strSkin = strSkin.replace("@", g_CfgPath);
        strSkin = strSkin.replace("~", g_strExeRoot);
        this->setStyleSheet(strSkin);
        fileSkin.close();
    }
}