Qt Widgets 的样式表由选择器和声明组成:QPushButton { color: white; } 先选择对象,再为匹配对象设置属性。它采用类似 CSS 的语法,但可用属性、子控件和状态由 Qt 控件实现决定,不能直接套用浏览器的全部 CSS 功能。
本页保留常用选择器、36 个子控件和44项状态的查阅表,并给出一套能加载资源文件的示例。排查具体对象没有命中规则的问题,可配合QSS 选择器与作用范围;组合按钮的背景处理见文件列表项悬停背景。
选择器:匹配哪个对象
跳转到“选择器:匹配哪个对象”| 类型 | 示例 | 匹配范围 |
|---|---|---|
| 通用 | * | 当前样式作用范围内的所有控件。 |
| 类型 | QPushButton | 该类型及其子类的实例。QWidget 范围更广,QGroupBox 则限定分组框。 |
| 属性 | QPushButton[flat="false"] | 属性值匹配的按钮;动态属性也可参与,但修改后可能需要重新应用样式。 |
| 类 | .QPushButton | 精确类名对应的实例,不包括派生类;并非网页中任意 CSS class 的自动映射。 |
| ID | QPushButton#myButton | 类型满足且 objectName() 为 myButton 的对象;单独 #myButton 不限定类型。 |
| 后代 | QDialog QPushButton | 父链中有 QDialog 的按钮,中间可有其他容器。 |
| 直接子对象 | QDialog > QPushButton | parentWidget() 就是该对话框的按钮。 |
例如 QLineEdit, QComboBox 是两条选择器的并集;QDialog QWidget 可能覆盖对话框中大量后代控件,需留意它会不会把局部颜色一起改掉。C++ 变量名不会自动成为 objectName。自定义类型选择器还依赖元对象中的类名。
子控件:匹配控件内部的样式部位
跳转到“子控件:匹配控件内部的样式部位”:: 后面是控件公开给样式系统的绘制部位,例如 QGroupBox::title。它不等于 C++ 子对象,因此不能用 QPushButton::item 选中按钮里的 QLabel。下表是查阅入口;使用前还要确认目标控件的支持说明。
| 子控件 | 典型用途 |
|---|---|
::add-line | 滚动条向增加方向移动一行的按钮。 |
::add-page | 滚动条滑块与增加方向按钮之间的分页区域。 |
::branch | 树视图的展开分支指示。 |
::chunk | 进度条已完成的色块。 |
::close-button | 停靠窗口或页签的关闭按钮。 |
::corner | 抽象滚动区域中两条滚动条的交会角。 |
::down-arrow | 组合框、表头排序、滚动条或数值输入框的向下箭头。 |
::down-button | QSpinBox 等数值输入框的减小按钮;滚动条用 ::add-line、::sub-line。 |
::drop-down | 组合框用于展开列表的按钮区域。 |
::float-button | 停靠窗口的浮动按钮。 |
::groove | 滑块控件的轨道。 |
::indicator | 复选框、单选框、可选菜单项、分组框或项目视图的勾选指示。 |
::handle | 滚动条、滑块或分隔器的可拖动部分。 |
::icon | 项目视图或菜单项中的图标。 |
::item | 项目视图、菜单栏、菜单或状态栏中的项。 |
::left-arrow | 滚动条等控件的向左箭头。 |
::left-corner | 页签容器的左侧角控件区域。 |
::menu-arrow | 带菜单的工具按钮中的菜单箭头。 |
::menu-button | 工具按钮采用独立菜单按钮模式时的菜单区域。 |
::menu-indicator | 按钮上的菜单指示;工具按钮也有相应支持。 |
::right-arrow | 子菜单或滚动条的向右箭头。 |
::pane | 页签容器内容区域的框架。 |
::right-corner | 页签容器的右侧角控件区域。 |
::scroller | 菜单或页签栏的滚动区域。 |
::section | 表头中的一个分区。 |
::separator | 菜单分隔线或主窗口停靠区域之间的分隔条。 |
::sub-line | 滚动条向减少方向移动一行的按钮。 |
::sub-page | 滚动条滑块与减少方向按钮之间的分页区域。 |
::tab | 页签栏或工具箱中的页签。 |
::tab-bar | 调整 QTabWidget 内页签栏的位置;单个页签外观仍用 ::tab。 |
::tear | 页签栏的截断提示部位。 |
::tearoff | 菜单的撕离提示部位。 |
::text | 项目视图中的文本部位。 |
::title | 分组框或停靠窗口的标题。 |
::up-arrow | 表头排序、滚动条或数值输入框的向上箭头;工具按钮也支持箭头部位。 |
::up-button | QSpinBox 等数值输入框的增大按钮。 |
组合框、滚动条等复杂控件在部分部位被自定义后,其他部位也可能需要明确设置尺寸和外观。不要把上表理解为每个控件都支持每个名字。Qt 6.8 参考表对 ::down-button 的滚动条归属有误;上表按 Qt 6.10.2 的子控件映射和控件实际绘制分发修正。
伪状态:限定何时应用
跳转到“伪状态:限定何时应用”单冒号 : 表示状态。连续状态表示同时满足,例如 QPushButton:hover:checked;! 表示否定,例如 QPushButton:hover:!pressed;逗号连接完整选择器表示“或”。
| 状态 | 含义与适用提示 |
|---|---|
:active | 控件所属窗口当前处于活动状态。 |
:adjoins-item | 树分支的连接部位邻接一个项目。 |
:alternate | 项目视图开启交替行颜色后,被绘制为交替行的项目。 |
:bottom | 部位位于底侧,例如底部页签。 |
:checked | 可勾选对象处于勾选状态。 |
:closable | 停靠窗口等对象允许关闭。 |
:closed | 树节点等对象处于折叠或关闭状态。 |
:default | 默认按钮或菜单默认动作。 |
:disabled | 对象已禁用。 |
:editable | 组合框允许编辑。 |
:edit-focus | 历史 Qt Extended 的编辑焦点状态;普通桌面键盘焦点使用 :focus。 |
:enabled | 对象已启用。 |
:exclusive | 菜单项等属于互斥选择组。 |
:first | 有序集合中的首项。 |
:flat | 按钮采用平面外观。 |
:floatable | 停靠窗口等对象允许浮动。 |
:focus | 对象具有输入焦点。 |
:has-children | 树节点拥有子项目。 |
:has-siblings | 树分支对应 State_Sibling;实际 Qt 6 解析器采用这个复数拼写。原稿的 :has-sibling 不应作为有效规则使用。 |
:horizontal | 控件或部位按水平方向布局。 |
:hover | 支持该状态的控件或部位处于鼠标悬停状态。 |
:indeterminate | 不确定状态,例如三态复选框的部分选中或不定进度。 |
:last | 有序集合中的末项。 |
:left | 部位位于左侧。 |
:maximized | 子窗口等对象处于最大化状态。 |
:middle | 位于集合中间,既非首项也非末项。 |
:minimized | 子窗口等对象处于最小化状态。 |
:movable | 停靠窗口等对象允许移动。 |
:no-frame | 数值输入框或单行输入框等没有边框。 |
:non-exclusive | 菜单项等不属于互斥选择组。 |
:off | 可切换对象处于关闭状态。 |
:on | 可切换对象处于开启状态。 |
:only-one | 集合中仅有这一项。 |
:open | 树节点已展开,或带菜单的控件已展开菜单。 |
:next-selected | 当前项的下一个相邻项已选中;不是“将要被选中”。 |
:pressed | 对象处于按下状态。 |
:previous-selected | 当前项的上一个相邻项已选中;不是历史选择记录。 |
:read-only | 输入框只读,或组合框不可编辑。 |
:right | 部位位于右侧。 |
:selected | 页签、菜单项等被选中;注意与按钮的 :checked 区别。 |
:top | 部位位于顶侧。 |
:unchecked | 可勾选对象处于未勾选状态。 |
:vertical | 控件或部位按垂直方向布局。 |
:window | 控件本身是窗口。 |
状态名存在不代表每一种控件都会产生这个状态。比如不能用普通 QLabel:hover 推断按钮同样的交互绘制;部分选中常见于三态 QCheckBox,不要据此假设标准 QRadioButton 也提供三态 API。表中名称以Qt 6.10.2 实际解析器及官方状态参考核对。
属性、值与盒模型
跳转到“属性、值与盒模型”| 属性 | 设置内容 |
|---|---|
color | 文本前景色。 |
background-color | 背景填充色。 |
border | 边线宽度、线型和颜色。 |
padding | 边线内侧与内容之间的空间。 |
margin | 边线外侧的空间。 |
font | 字体及字号等;示例的 14px 是像素,不是 14 点。 |
selection-color | 所选文本的前景色,要求控件支持。 |
selection-background-color | 所选文本的背景色,要求控件支持。 |
属性值需要满足 Qt 的类型要求,例如颜色、长度或字体描述。支持盒模型的控件或子控件可按下面四层理解:外边距 margin,边框 border,内边距 padding,最后是内容区。默认边距、边框宽度和内边距都是零;实际样式可以改变它们。

这张原图用于说明同心矩形的关系。QSS 边距和布局管理器的 setContentsMargins()、setSpacing() 属于不同设置,不能仅凭图示就认定它们会替代彼此。Qt 盒模型说明还说明了背景绘制和裁剪的边界。

第二张图展示一种盒模型检查面板,不能据此确定使用的是哪个工具,也不能把其中约 229.45 × 24 的内容尺寸直接当作 Qt 控件的实际几何测量。
规则冲突如何判断
跳转到“规则冲突如何判断”先判断规则来自哪个层级,再比较同层级选择器。控件自己的样式优先于祖先或应用级样式;在同一层级,按 ID、属性及伪状态、类型名的具体性比较,同等具体性时后写的规则胜出。C++ 派生类不会因此获得更高的类型选择器优先级,QSS 也不支持 !important。
例如同一份样式中的 QPushButton#okButton { color: gray; } 比 QPushButton { color: red; } 更具体,按钮文字为灰色。QPushButton:hover:checked 比 QPushButton:hover 多一个状态条件,但不能因此覆盖具有更高 ID 具体性的规则。多个状态同时满足时,应明确期望的组合规则,避免只凭书写位置猜颜色。
下面示例让 stateButton 的普通文字为红色,悬停或勾选时为白色,同时满足时为蓝色;按钮背景展示红色、橙色和按下的绿色。为便于辨认红色文字,stateButton 的普通底色单独设为浅灰。okButton 保留 ID 规则的灰色文字。
可运行示例:从资源加载 QSS
跳转到“可运行示例:从资源加载 QSS”创建同一目录中的三个文件。先保存 theme.qss:
QWidget { background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font: 14px "Arial";}QPushButton { background-color: rgb(255, 0, 0); color: white; border: 2px solid black; border-radius: 10px; padding: 5px;}QPushButton#okButton { color: gray; }QPushButton:hover { background-color: rgb(255, 165, 0); }QPushButton:pressed { background-color: rgb(0, 255, 0); }QPushButton#stateButton { color: red; background-color: rgb(245, 245, 245);}QPushButton#stateButton:hover { background-color: rgb(255, 165, 0); }QPushButton#stateButton:pressed { background-color: rgb(0, 255, 0); }QPushButton#stateButton:hover, QPushButton#stateButton:checked { color: white;}QPushButton#stateButton:hover:checked { color: blue; }QWidget#filemanager_memeryArea { background-color: rgb(228, 228, 228); border-radius: 5px;}QGroupBox { border: 1px solid gray; margin-top: 14px;}QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top center; padding: 0 3px; background-color: rgb(200, 200, 200);}QLineEdit, QComboBox { background-color: white; border: 1px solid black;}QLineEdit { selection-color: white; selection-background-color: rgb(40, 90, 160);}再保存 main.cpp。文件只检查“存在”并不等于能够读取,因此直接检查 open() 和流读取结果;读取失败时保留已有样式并返回错误。
#include <QApplication>#include <QComboBox>#include <QDebug>#include <QFile>#include <QFrame>#include <QGroupBox>#include <QLabel>#include <QLineEdit>#include <QPushButton>#include <QStringConverter>#include <QTextStream>#include <QVBoxLayout>#include <cstdlib>
bool loadStyleSheet(QApplication &app, const QString &path, QString *error = nullptr) { QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (error) *error = file.errorString(); return false; } QTextStream stream(&file); stream.setEncoding(QStringConverter::Utf8); const QString text = stream.readAll(); if (stream.status() != QTextStream::Ok || file.error() != QFile::NoError) { if (error) *error = QStringLiteral("Failed to read stylesheet"); return false; } app.setStyleSheet(text); if (error) error->clear(); return true;}
QWidget *makeWindow() { auto *window = new QWidget; auto *column = new QVBoxLayout(window); auto *area = new QFrame(window); area->setObjectName("filemanager_memeryArea"); auto *areaLayout = new QVBoxLayout(area); areaLayout->addWidget(new QLabel("File area", area)); auto *ok = new QPushButton("Object-name rule", area); ok->setObjectName("okButton"); areaLayout->addWidget(ok); auto *state = new QPushButton("Hover / check / press", area); state->setObjectName("stateButton"); state->setCheckable(true); areaLayout->addWidget(state); column->addWidget(area);
auto *group = new QGroupBox("Inputs", window); group->setObjectName("inputs"); auto *inputs = new QVBoxLayout(group); inputs->setContentsMargins(10, 16, 10, 10); auto *line = new QLineEdit("Select this text", group); line->setObjectName("line"); auto *combo = new QComboBox(group); combo->setObjectName("combo"); combo->addItems({"One", "Two"}); inputs->addWidget(line); inputs->addWidget(combo); column->addWidget(group); window->setWindowTitle("QSS reference example"); window->resize(460, 300); return window;}
int main(int argc, char *argv[]) { QApplication app(argc, argv); const QString path = QStringLiteral(":/styles/theme.qss"); QString error; if (!loadStyleSheet(app, path, &error)) { qWarning().noquote() << path << error; return EXIT_FAILURE; } QWidget *window = makeWindow(); window->setAttribute(Qt::WA_DeleteOnClose); window->show(); return app.exec();}最后保存 CMakeLists.txt。qt_add_resources() 把 theme.qss 编译到程序资源中,文件名和前缀共同形成 :/styles/theme.qss。
cmake_minimum_required(VERSION 3.21)project(QssReferenceExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt6 REQUIRED COMPONENTS Widgets)add_executable(qss-reference-example main.cpp)target_link_libraries(qss-reference-example PRIVATE Qt6::Widgets)qt_add_resources(qss-reference-example styles PREFIX "/styles" FILES theme.qss)原笔记使用的 :/qdarkstyle/dark/darkstyle.qss 只有在相应资源确实被打包或注册时才可读取;这个路径本身不会安装第三方主题。改为磁盘路径时,同样经过读取失败处理。成功返回表示读取并提交了字符串,不表示已经校验所有 QSS 规则;语法和外观仍需通过 Qt 的诊断输出及实际控件检查。
这里的全局 QWidget 规则会直接匹配大量子控件,所以灰色区域内的标签仍可能拥有自己的白色背景。若期望标签透出父背景,应像列表项示例一样给目标标签设透明背景,避免把“全局匹配”误认为普通属性继承。
验证与使用边界
跳转到“验证与使用边界”示例按 Qt 6.10.2、C++17 构建,检查资源成功加载、路径不存在时保留旧样式,以及示例控件的颜色、字号和组合状态。速查表是名称及适用范围核对,并不代表对每个控件的每项状态都进行了交互测试。自动绘制检查使用离屏平台和 Fusion 样式,部署平台的字体、原生菜单与窗口部件仍可能表现不同。
参考
跳转到“参考”- Qt 样式表语法
- Qt 样式表参考
- Qt 盒模型与部件定制
- 原始学习笔记,首次发布于 2025-05-13。