找回密码
 立即注册
搜索
查看: 325|回复: 0

初识 QSS

[复制链接]

266

主题

0

回帖

1119

积分

管理员

积分
1119
发表于 2023-12-19 00:55:29 | 显示全部楼层 |阅读模式

简介

CSS( Cascading Style Sheets,层叠样式表)把现在的网页打扮的或花枝招展、或简约朴素。使用 CSS 将结构和表现分离的设计理念启发了 Qt 的样式设计,于是出现了 QSS( Qt Style Sheets ),给界面的开发增添了极大的灵活性。这就好比界面部件( Widget )结构化了人的衣着(帽子、上衣、裙子、鞋子),QSS 则定义了这些衣服的颜色、花纹等样式,每天只需关注换什么样式即可,不用去想要不要穿裙子(当然,你非要穿裤子也是没问题的)。

语法结构

在语法上 QSS 与 CSS 大体上是一致的,由两个主要的部分构成:选择器( selector ),以及一条或多条声明( declaration )。

selector {
  declaration1;
  declaration2;
  ...
  declarationN
}

选择器

选择器是我们的 widget,比如 QPushButton、QLineEdit 等,可以使用星号 * 来匹配所有的选择器。当界面上有多个 QLineEdit ,而我们却只想改变特定 QLineEdit 的样式时可以使用 QObject::setObjectName() 给那个 QLineEdit 命个名字,然后使用 ID 选择器来设置样式表。

QLineEdit#nameEdit { background-color: yellow }

当然了,我们也可以直接修改一个部件的样式表,像这样:

nameEdit->setStyleSheet("color: blue;"
                        "background-color: yellow;"
                        "selection-color: yellow;"
                        "selection-background-color: blue;");

从上边的例子不难看出声明( declaration )的结构应该是这样的:

property: value

property 是要设置的样式属性名,value 则是它的值。比如 border、background、margin、padding 等都是属性名。属性和值之间用冒号隔开,两条声明间用分号隔开。声明中的大小写是不敏感的。

盒子模型( The Box Model )

怎么理解 padding、border、margin 这些属性呢?

当使用样式表的时候,每个部件( widget )都被当作一个由四个同心矩形组成的盒子来对待。这四个矩形是 the margin rectangle、the border(边框) rectangle、the padding rectangle 和 the content(内容) rectangle 。

margin、border-width 和 padding 的默认值是 0 ,所以这四个矩形看起来是大小一致的。属性中的 background 是指 border 里边的背景,也就是 padding 矩形区域。盒子的渲染步骤为:

  1. 设置整个渲染操作的剪辑区域(如 border-radius 边角半径属性);
  2. 绘制背景(如 background-image 属性);
  3. 绘制边框(如 border-image, border 属性);
  4. 绘制叠加图像(如 image 属性);

子控件( Sub-controls )

一些复杂的部件还包含一些子控件,比如 QComboBox(下拉列表框部件)。它含有一个下拉按钮子控件,下拉按钮控件又含有一个下拉箭头子控件。用 QComboBox::drop-down 做下拉按钮的选择器,用 QComboBox::down-arrow 做下拉箭头的选择器。子控件是以双冒号开头的。

伪状态( Pseudo-States )

选择器与伪状态结合起来可以限定部件在某一状态下的样式,伪状态以单个冒号开头。比较常用的比如 :hover ,表示鼠标在部件上时候的状态。伪状态支持非运算符, !:hover 则表示鼠标不在部件上的时候。既然有非逻辑,那么有没有与和或逻辑呢?

这些可以有,当多个伪状态连着写就表示他们之间是与的关系,下例为对 QRadioButton::indicator 选择器各状态的样式定义:

QRadioButton::indicator {
  width: 13px;
  height: 13px;
}

QRadioButton::indicator:unchecked {
  image: url(:/images/radiobutton_unchecked.png);
}

QRadioButton::indicator:unchecked:hover {
  image: url(:/images/radiobutton_unchecked_hover.png);
}

QRadioButton::indicator:unchecked:pressed {
  image: url(:/images/radiobutton_unchecked_pressed.png);
}

QRadioButton::indicator:checked {
  image: url(:/images/radiobutton_checked.png);
}

QRadioButton::indicator:checked:hover {
  image: url(:/images/radiobutton_checked_hover.png);
}

QRadioButton::indicator:checked:pressed {
  image: url(:/images/radiobutton_checked_pressed.png);
}

当多个选择器间用逗号分割时,他们之间是或逻辑。如下实例中有对 QPushButton::menu-indicator 按下或者打开状态下样式的定义:

QPushButton:open { /* when the button has its menu open */
  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                    stop: 0 #dadbde, stop: 1 #f6f7fa);
}

QPushButton::menu-indicator {
  image: url(menu_indicator.png);
  subcontrol-origin: padding;
  subcontrol-position: bottom right;
}

QPushButton::menu-indicator:pressed, QPushButton::menu-indicator:open {
  position: relative;
  top: 2px; left: 2px; /* shift the arrow by 2 px */
}

动态属性( Dynamic Properties )

动态属性的格式是在选择器后加上带中括号的属性限定表达式,比如通过以下操作将三个输入框的背景色改为黄色:

*[mandatoryField="true"] { background-color: yellow }

QLineEdit *nameEdit = new QLineEdit(this);
nameEdit->setProperty("mandatoryField", true);

QLineEdit *emailEdit = new QLineEdit(this);
emailEdit->setProperty("mandatoryField", true);

QSpinBox *ageSpinBox = new QSpinBox(this);
ageSpinBox->setProperty("mandatoryField", true);

改变 QPushButton 的默认样式

对 QSS 有个大致的了解后,不妨来做一个实验,修改 QPushButton 的默认样式。一般情况下按钮有三个状态:普通状态、鼠标悬停上方时的状态、鼠标按下后的状态。如果要做出较为复杂的显示效果,一般会以 PNG 图片的形式展现。可以做出三幅图片,也可以将三个状态并列地做在一幅图片上,这里我们选择后者。

图中每个状态的尺寸为 99px 34px ,正副图的尺寸为 297px 34px 。虽然在三个状态下使用同一幅图片,但我们要显示不同的图片区间。在样式表里我使用了 border-image ,而没有使用 background ,原因是目前的 background 还不支持对图片的绝对位置的切割。

border-image 是从 CSS3 开始引入的一个非常好用的属性,在 QSS 中同样支持。它的原理是将图片以九宫格的形式分割并绘制在边框矩形中,四个角的四格图片保持不变,可以设置其余格子中图片拉伸、压缩、平铺等,从而保持在变换过程中图片整体更加自然。

border-image 的语法为:

border-image: none | <image> [ <number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [ stretch | repeat | round ]{0,2}

在我们这次的命题里不用边缘部分的 8 个格,只用中间格的切割部分( border: 0px ),各状态切割如下图:

普通状态切割参数为 0 198 0 0

鼠标悬停上方时的状态切割参数为 0 99 0 99

鼠标按下后的状态切割参数为 0 0 0 198

这次先不使用 .qss 样式表文件,直接在 QtCreator 的部件属性 StyleSheet 里设置:

QPushButton{
  color: white;
  font: bold 10pt;
  border: 0px;
  border-image: url(../untitled1/button.png) 0 198 0 0;
}

QPushButton:hover{
  border-image: url(../untitled1/button.png) 0 99 0 99;
}

QPushButton:pressed {
  border-image: url(../untitled1/button.png) 0 0 0 198;
  padding-top: 2px;
  padding-left: 2px;
}

运行效果:

参考资料

  1. Qt Style Sheets http://doc.qt.io/qt-5/stylesheet.html
  2. Qt Style Sheets Reference http://doc.qt.io/qt-5/stylesheet-reference.html
  3. Qt Style Sheets Examples http://doc.qt.io/qt-5/stylesheet-examples.html
  4. Border Images http://www.w3.org/TR/css3-background/#border-images

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|棱讯科技 ( 粤ICP备2024228160号-2|粤公网安备44030002003510号 )

GMT+8, 2024-7-27 19:22 , Processed in 0.018487 second(s), 3 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表