Qt QSS 选择器和 CSS2、CSS3 的选择器类似,建议先学习或者复习 CSS 选择器的语法。
QSS 虽然源自 CSS ,但也有稍许不同,而且支持的语法也没 CSS 那么多。
一、选择器类型
1.1 类选择器
1 | /* |
1.2 选择器分组
1 | /*同时匹配QPushButton、QLineEdit的实例 |
1.3 ID 选择器
1 | /* |
1.4 属性选择器
1 | /* |
1.5 后代选择器
1 | /* |
1.6 子元素选择器
1 | /* |
1.7 伪状态
1 | /* |
1.8 子控件选择器
1 | QRadioButton::indicator::unchecked:disabled { |
二、选择器优先级
一句话归纳为:优先使用更具体的选择器。
具体实例如下:
1 | /* |
1 | /* |
1 | /* |
1 | /* |
1 | /* |
三、类型、属性、伪状态、子控件
关于 QSS 支持哪些类型、每种类型支持哪些属性、伪状态和子控件,在 Qt 的官方的英文文档中有详细的介绍:
《Qt Style Sheets Reference》
也可以在Qt Assistant中搜索”Qt Style Sheets Reference”打开帮助文档。
3.1 伪状态列表
为了方便查阅,这里列举出QSS目前支持的所有伪状态。
伪状态都是以一个冒号
:
开头,如:active
。
伪状态 | 描述 |
---|---|
:active | 此状态在Widget驻留在活动窗口时设置 |
:adjoins-item | 此状态在QTreeView的::branch与一个item相邻时设置 |
:alternate | 当QAbstractItemView::alternatingRowColors()设置为真时,在绘制QAbstractItemView的行时,为每个交替行设置此状态 |
:bottom | 此item位于底部时设置。例如,QTabBar有位于底部的选项卡 |
:checked | 此item被选中时设置。例如,QAbstractButton的checked状态 |
:closable | 此item可以被关闭时设置。例如,QDockWidget的QDockWidget::DockWidgetClosable特性开启时 |
:closed | 此item处于关闭状态时设置。例如,QTreeView中未展开的item |
:default | 此item的默认状态时设置。例如,一个default的QPushButton或QMenu中的一个默认动作 |
:disabled | 此item被禁用时设置 |
:editable | 如QComboBox是可编辑时设置 |
:edit-focus | 此item具有编辑焦点(参考QStyle::State_HasEditFocus)时设置。此状态仅对Qt扩展应用程序可用 |
:enabled | 此item已启用时设置 |
:exclusive | 此item是属于某个独占组时设置。例如,独占QActionGroup中的菜单项 |
:first | 此item是列表中的第一项时设置。例如,QTabBar中的第一个选项卡 |
:flat | 此item是扁平时设置。例如,一个扁平的QPushButton |
:floatable | 此item可以浮动时设置。例如,QDockWidget的QDockWidget::DockWidgetFloatable的特性开启时 |
:focus | 此item具有输入焦点时设置 |
:has-children | 此item具有子对象时设置。例如,QTreeView中具有子项的项 |
:has-sibling | 此item具有兄弟对象时设置。例如,QTreeView中与之相邻的项 |
:horizontal | 此item处于水平方向时设置 |
:hover | 鼠标悬浮在此item上时设置 |
:indeterminate | 此item处于不确定状态时设置。例如,QCheckBox或QRadioButton被部分选中 |
:last | 此item是列表中的最后一项时设置。例如,QTabBar中的最后一个选项卡 |
:left | 此item位于左侧时设置。例如,QTabBar有位于左侧的选项卡 |
:maximized | 此item处于最大化状态时设置。例如,一个最大化的QMdiSubWindow |
:middle | 此item是列表中的中间一项时设置。例如,一个不在QTabBar中的开头或结尾的选项卡 |
:minimized | 此item处于最小化状态时设置。例如,一个最小化的QMdiSubWindow |
:movable | 此item可以被移动时设置。例如, QDockWidget的QDockWidget::DockWidgetMovable特性开启时 |
:no-frame | 此item没有边框时设置。例如,没有边框的QSpinBox或QLineEdit |
:non-exclusive | 此item是属于非独占组时设置。例如,非独占QActionGroup中的菜单项 |
:off | 对可以切换的items,这适用于处于off状态的item |
:on | 对可以切换的items,这适用于处于on状态的widget |
:only-one | 此item是列表中的唯一项时设置。例如,一个在QTabBar中单独的选项卡 |
:open | 此item处于打开状态时设置。例如,QTreeView中的展开项,或带有菜单的QComboBox或QPushButton |
:next-selected | 此item是列表中的下一个被选中的项时设置。例如,在QTabBar中当前选项卡的下一个要选中的选项卡 |
:pressed | 鼠标正在按压在此item上时设置 |
:previous-selected | 此item是列表中的上一个被选中的项时设置。例如,在QTabBar中当前选项卡的上一个要选中的选项卡 |
:read-only | 此item处于只读或不可编辑状态时设置。例如,一个只读QLineEdit或不可编辑的QComboBox |
:right | 此item位于右侧时设置。例如,QTabBar有位于右侧的选项卡 |
:selected | 此item处于选中状态时设置。例如,一个在QTabBar中被选中的选项卡或一个在菜单中被选中的菜单项 |
:top | 此item位于顶部时设置。例如,QTabBar有位于顶部的选项卡 |
:unchecked | 此item处于未被选中状态时设置 |
:vertical | 此item处于垂直方向时设置 |
:window | Widget是一个窗口(例如,一个顶层Widget)时设置 |
3.2 子控件列表
伪状态都是以两个冒号
::
开头,如::item
。
子控件 | 描述 |
---|---|
::add-line | 在QScrollBar中跳转下一行的按钮 |
::add-page | 在QScrollBar中滑动条和add-line之间的区域 |
::branch | 在QTreeView中的分支指示器 |
::chunk | 在QProgressBar中的进度块 |
::close-button | 在QDockWidget或QTabBar选项卡的关闭按钮 |
::corner | 在QAbstractScrollArea中两个滚动条之间的角落 |
::down-arrow | 在QComboBox、QHeaderView(排序指示器)、QScrollBar或QSpinBox的向下箭头 |
::down-button | 在QScrollBar或QSpinBox中的向下按钮 |
::drop-down | 在QComboBox中的下拉框 |
::float-button | 在QDockWidget中的浮动按钮 |
::groove | 在QSlider中的滑动槽 |
::indicator | 在QAbstractItemVIew、QCheckBox、QRadioButton、可选中的菜单项或可选中的QGroupBox中的指示器 |
::handle | 在QScrollBar、QSplitter和QSlider中的操作条(滑动条) |
::icon | 在QAbstractItemVIew或QMenu中的图标 |
::item | 在QAbstractItemVIew、QMenuBar、QMenu或QStatuBar中的一项 |
::left-arrow | 在QScrollBar中的向左箭头 |
::left-corner | 在QTabWidget中的左上角 |
::menu-arrow | 带有菜单的QToolButton中的箭头 |
::menu-button | 在QToolButton中的菜单按钮 |
::menu-indicator | 在QPushButton中的菜单指示器 |
::right-arrow | 在QMenu或QScrollBar中的向右箭头 |
::pane | 在QTabWidget中的边或框 |
::right-corner | 在QTabWidget中的右上角 |
::scroller | 在QMenu或QTabBar中的滚动条 |
::section | 在QHeaderView中的区块 |
::separator | 在QMenu或QMainWIndow中分隔条 |
::sub-line | 在QScrollBar中跳转上一行的按钮 |
::sub-page | 在QScrollBar中滑动条和sub-line之间的区域 |
::tab | 在QTabBar或QToolBox中选项卡 |
::tab-bar | 在QTabWidget中的选项卡栏 |
::tear | 在QTabBar中的tear指示器 |
::tearoff | 在QMenu中的tear-off指示器 |
::text | 在QAbstractItemView中的文本 |
::title | 在QGroupBox或QDockWidget中的标题栏 |
::up-arrow | 在QComboBox、QHeaderView(排序指示器)、QScrollBar或QSpinBox的向上箭头 |
::up-button | 在QScrollBar或QSpinBox中的向上按钮 |
使用示例:
1 | QPushButton#btnTest::menu-indicator { |
同时使用伪状态和子控件时,先指定子控件,后指定伪状态:
1 | QComboBox::down-arrow:disabled{ |
四、盒子模型
在使用 QSS 设置样式时,有一个关键的概念需要知晓,那就是“盒子模型”(即Box Model
)。
每个 Widget 都被视为具有 4 个同心矩形的框:
MARGIN矩形、BORDER矩形、PADDING矩形和 CONTENT矩形,上图标注了每个矩形的区域。
默认情况下MARGIN矩形、BORDER矩形、PADDING矩形的宽度都为 0,这样在默认情况下,4 个矩形就重合为 1 个CONTENT矩形了。
同样,默认情况下 background-image 指定的背景,只在 border 内的区域绘制,但我们也可以使用 background-clip 或 background-origin 属性来更改这种默认行为。
如何实现背景图像随 Widget 大小自动缩放?
background-image 指定的背景图像无法随 Widget 大小自动缩放,要提供可以随 Widget 大小缩放的背景图像可以使用border-image
和image
属性,二者区别如下:
- border-image 属性指定的图像从 border 及其内的区域开始绘制,会导致 border 属性被覆盖。
- image 属性指定的图像从绘制到 content 区域内,image 指定的 url 为 SVG 图像,则支持自动缩放,非 SVG 图像仅支持自动缩小。
五、动态属性
通过 setProperty 方法设置 QWidget 对象属性,在 QSS 中可以根据不同的属性值应用不同的样式。
例如,设置 pushButtonMax 按钮的 isMax 属性,表示当前窗口是否最大化:
1 | pushButtonMax->setProperty("isMax", this->isMaximized() ? true : false); |
在 QSS 中根据不同的属性值应用不同的样式:
1 | #pushButtonMax[isMax="false"] { |
六、Q_PROPERTY
在 Qt 中可以使用Q_PROPERTY
宏为 QObject 对象(含子对象)声明属性,任何被Q_PROPERTY
声明的属性都能在 QSS 中使用qproperty-<property name>
语法进行设置。
以 QToolButton 为例,QToolButton 继承至 QAbstractButton,QAbstractButton 拥有以下被 Q_PROPERTY 声明的属性:
1 | class Q_WIDGETS_EXPORT QAbstractButton : public QWidget |
在 QSS 中可以直接对属性赋值,如:
1 | QToolButton { |
七、Padding和Margin的使用
Margin 指控件和其他控件的间距,而 Padding 指控件内的内容与边框的间距。
二者的语法与CSS中的一样:
1 | margin: 25px 50px 75px 100px; |
从左到右依次为:上、右、下、左。
支持简写形式:
1 | margin: 25px 50px; |
表示:上下间距为25px,左右间距为50px。
八、几种图片设置方法
大家在使用 QSS 进行图片设置时,也许被 image, border-image, background-image 这几个属性的差异困扰过,下面就来讲解一下这个几个属性的异同点。
8.1 background-image
background-image 按图片实际尺寸显示图片,超过控件显示区域的部分会被裁剪掉。
虽能显示 SVG,但无法对 SVG 进行无损缩放;
关于 background-image 的几个附属属性的作用,可以一句话概括为:
从 background-origin 区域的 background-position 位置开始绘制图像,并以 background-repeat 方式进行重复;最后将图像 background-clip 区域以外的范围裁剪掉(即不显示)。
8.2 image
image 会将图片按图片原长宽比进行缩放,并保证填充满控件 content 区域。
image 支持 SVG 矢量图显示和无损缩放。
image 可以使用 image-position 来指定图片开始显示的位置(参考上面background-position
)。
8.3 border-image
按控件 border 区域的长宽比来缩放图片,保证填充满控件 border 区域,支持 SVG 矢量图显示和无损缩放;
8.4 绘制顺序
如果在一个控件中同时指定background-image,border-image,image 这三个属性,会按照如下的顺序进行绘制:
1 | 先绘制 background-image |
8.5 示例
1 | QPushButton#pushButton4 { |
九、QSS编辑器
QSS 样式的编写是一个熟能生巧的过程,不仅不需要熟记常用的样式属性,还需要勤加练习,多多验证,灵活运用。
为了方便学习和验证 QSS 样式,我开发了一个 QSS 编辑器,通过该编辑器可以实时预览 QSS 的生效样式,而且编辑器还内置了两套完整的QSS主题,方便初学者学习 QSS 属性。
项目地址: