Qt样式表详解(附带实例)
Qt 样式表是一个可以自定义部件外观的十分强大的机制,Qt 样式表的概念、术语和语法都受到了 HTML 的层叠样式表(Cascading Style Sheets,CSS)的启发,不过与 CSS 不同的是,Qt 样式表应用于部件的世界。
样式表可以使用 QApplication::setStyleSheet() 函数将其设置到整个应用程序上,也可以使用 QWidget::setStyleSheet() 函数将其设置到一个指定的部件(还有它的子部件)上。如果在不同的级别都设置了样式表,那么 Qt 会使用所有有效的样式表,这被称为样式表的层叠。
下面看一个简单的例子。使用代码设置样式表,新建 Qt Widgets 应用,项目名称为 mystylesheets,类名为 MainWindow,基类为 QMainWindow 保持不变。建立好项目后进入设计模式,向界面上拖入一个 Push Button 和一个 Horizontal Slider 部件,然后在 mainwindow.cpp 文件的构造函数里添加如下代码:
先注释掉上面的两行代码,然后添加如下代码:

图 1 在设计模式编辑样式表
这时会弹出“选择颜色”对话框,可以随便选择一个颜色,然后单击“确定”按钮,则自动添加如下代码:
相似的,可以再设置 QSlider 的背景色。在设计模式,有时无法正常显示设置好的样式表效果,不过运行程序后会正常显示。这里是在 MainWindow 界面上设置了样式表,当然,也可以按照这种方法在指定的部件上添加样式表。
例如:
Qt 样式表中一般不区分大小写,例如 color、Color、COLOR 和 COloR 表示相同的属性。只有类名、对象名和 Qt 属性名是区分大小写的。
一些选择器可以指定相同的声明,各选择器使用逗号隔开,例如:
样式规则的声明部分是一些“属性:值”对组成的列表,它们包含在大括号中,使用分号隔开。例如:
选择器可以包含子控件来对部件的特定子控件应用规则,例如:
伪状态可以使用感叹号来表示否定,例如要当鼠标没有悬停在一个 QRadioButton 上时才应用规则,那么这个规则可以写为:
伪状态还可以多个连用,达到逻辑与效果,例如当鼠标悬停在一个被选中的 QCheckBox 部件上时才应用规则,那么这个规则可以写为:
如果有需要,也可以使用逗号来表示逻辑或操作,例如:
当然,伪状态也可以和子控件联合使用:
解决这个冲突的原则是:特殊的选择器优先。因为 QPushButton#okButton 一般代表一个单一的对象,而不是一个类所有的实例,所以它比 QPushButton 更特殊,那么这时便会使用第一个规则,okButton 的文本颜色为灰色。
相似的,有伪状态比没有伪状态优先。如果两个选择符的特殊性相同,则后面出现的比前面的优先。Qt 样式表使用 CSS2 规范来确定规则的特殊性。
部件有效的样式表是通过部件祖先的样式表和 QApplication 上的样式表合并得到的。当发生冲突时,部件自己的样式表优先于任何继承的样式表,同样,父部件的样式表优先于祖先的样式表。
例如,一个 QPushButton 包含在一个 QGroupBox 中,这里对 QGroupBox 设置样式表:
如果想要 QGroupBox 的颜色设置到其子部件上,可以这样设置样式表:

图 2 盒子模型示意图
这 4 个矩形分别是内容(content)、填衬(padding)、边框(border)和边距(margin)。边距、边框宽度和填衬等属性的默认值都是 0,这样 4 个矩形恰好重合。
可以使用 background-image 属性来为部件指定一个背景。默认 background-image 只在边框以内的区域进行绘制,这个可以使用 background-clip 属性来进行更改。还可以使用 background-repeat 和 background-origin 来控制背景图片的重复方式以及原点。
一个 background-image 无法随着部件的大小来自动缩放,如果想要背景随着部件的大小变化,那就必须使用 border-image。如果同时指定了 background-image 和 border-image,那么 border-image 会绘制在 background-image 之上。
此外,image 属性可以用来在 border-image 之上绘制一个图片。如果使用 image 指定的图片的大小与部件的大小不匹配,那么它不会平铺或者拉伸。图片的对齐方式可以使用 image-position 属性来设置。
首先向项目目录中添加 3 张图片,再向项目中添加一个 Qt 资源文件,名称为 myresource。
建立完成后,先添加前缀 /images,然后将项目目录中的 3 张图片添加进来,最后按下 Ctrl+S 快捷键进行保存。
完成后进入设计模式,再次打开主界面的“编辑样式表”对话框,先清空以前的代码,再添加如下代码:
下面先在前面的程序中添加新文件,模板选择概要分类中的 Empty File,名称为 my.qss。建立完成后,将前面在主界面的“编辑样式表”对话框中的内容全部剪切到这个文件中(注意:要将“编辑样式表”对话框中的内容清空)。然后按下 Ctrl+S 快捷键保存该文件。
在 myresource.qrc 文件上右击,在弹出的快捷菜单中选择“用...打开→资源编辑器”菜单项,打开资源文件。然后添加一个 /qss 前缀(添加这个前缀只是为了将文件区分开),再选择项目目录下新添加的 my.qss 文件。最后按下 Ctrl+S 快捷键保存修改。
下面先打开 mainwindow.h 文件,添加类前置声明:
样式表可以使用 QApplication::setStyleSheet() 函数将其设置到整个应用程序上,也可以使用 QWidget::setStyleSheet() 函数将其设置到一个指定的部件(还有它的子部件)上。如果在不同的级别都设置了样式表,那么 Qt 会使用所有有效的样式表,这被称为样式表的层叠。
下面看一个简单的例子。使用代码设置样式表,新建 Qt Widgets 应用,项目名称为 mystylesheets,类名为 MainWindow,基类为 QMainWindow 保持不变。建立好项目后进入设计模式,向界面上拖入一个 Push Button 和一个 Horizontal Slider 部件,然后在 mainwindow.cpp 文件的构造函数里添加如下代码:
ui->pushButton->setStyleSheet("background:yellow"); ui->horizontalSlider->setStyleSheet("background:blue");这样便设置了两个部件的背景色,可以运行程序查看效果。不过像这样调用指定部件的 setStyleSheet() 函数,只会对这个部件应用该样式表,如果想对所有相同部件都使用相同的样式表,那么可以在它们的父部件上设置样式表。因为这里两个部件都在 MainWindow上,所以可以为 MainWindow 设置样式表。
先注释掉上面的两行代码,然后添加如下代码:
setStyleSheet("QPushButton{background:yellow}QSlider{background:blue}");这样,以后向主窗口上添加的所有 QPushButton 部件和 QSlider 部件的背景色都会改为这里指定的颜色。除了使用代码来设置样式表,也可以在设计模式中为添加到界面上的部件设置样式表,这样更加直观。
在设计模式中设置样式表
先注释掉上面添加的代码,然后进入设计模式。在界面上右击,在弹出的快捷菜单中选择“改变样式表”,这时会出现“编辑样式表”对话框,在其中输入如下代码:QPushButton{ }注意光标留在第一个大括号后。然后单击“添加颜色”选项后面的下拉箭头,在弹出的列表中选择 background-color 一项,如下图所示:

图 1 在设计模式编辑样式表
这时会弹出“选择颜色”对话框,可以随便选择一个颜色,然后单击“确定”按钮,则自动添加如下代码:
QPushButton{ background-color: rgb(85, 170, 127); }根据选择颜色的不同,rgb() 中参数的数值也会不同。可以看到,这里设置样式表不仅很便捷,而且很直观,不仅可以设置颜色,还可以使用图片,使用渐变颜色或者更改字体。
相似的,可以再设置 QSlider 的背景色。在设计模式,有时无法正常显示设置好的样式表效果,不过运行程序后会正常显示。这里是在 MainWindow 界面上设置了样式表,当然,也可以按照这种方法在指定的部件上添加样式表。
Qt样式表语法
Qt 样式表的术语和语法规则与 HTML CSS 基本相同,下面从样式规则、选择器类型、子控件等几个方面来进行讲解。1) 样式规则
样式表包含了一系列的样式规则,每个样式规则由选择器(selector)和声明(declaration)组成。选择器指定了受该规则影响的部件;声明指定了这个部件上要设置的属性。例如:
QPushButton{color:red}在这个样式规则中,QPushButton 是选择器,{color:red} 是声明,其中 color 是属性,red 是值。这个规则指定了 QPushButton 和它的子类应该使用红色作为前景色。
Qt 样式表中一般不区分大小写,例如 color、Color、COLOR 和 COloR 表示相同的属性。只有类名、对象名和 Qt 属性名是区分大小写的。
一些选择器可以指定相同的声明,各选择器使用逗号隔开,例如:
QPushButton,QLineEdit,QComboBox{color:red}
样式规则的声明部分是一些“属性:值”对组成的列表,它们包含在大括号中,使用分号隔开。例如:
QPushButton{color:red;background-color:white}可以在 Qt Style Sheets Reference 关键字对应的文档中查看 Qt 样式表所支持的所有部件及其属性。
2) 选择器类型
Qt 样式表支持在 CSS2 中定义的所有选择器。下表列出了常用的选择器类型。选择器 | 示例 | 说明 |
---|---|---|
通用选择器 | * | 匹配所有部件 |
类型选择器 | QPushButton | 匹配所有 QPushButton 实例和它的所有子类 |
属性选择器 | QPushButton[flat="false"] | 匹配 QPushButton 的 flat 属性为false的实例 |
类选择器 | .QPushButton | 匹配所有 QPushButton 实例,但不包含它的子类 |
ID选择器 | QPushButton#okButton | 匹配所有 QPushButton 中以 okButton 为对象名的实例 |
后代选择器 | QDialog QPushButton | 匹配所有 QPushButton 实例,它们必须是 QDialog 的子孙部件 |
孩子选择器 | QDialog>QPushButton | 匹配所有 QPushButton 实例,它们必须是 QDialog 的直接子部件 |
3) 子控件(Sub-Controls)
对一些复杂的部件修改样式,可能需要访问它们的子控件,例如 QComboBox 的下拉按钮,还有 QSpinBox 的向上和向下箭头等。选择器可以包含子控件来对部件的特定子控件应用规则,例如:
QComboBox::drop-down{image:url(dropdown.png)}这样的规则可以改变所有的 QComboBox 部件的下拉按钮的样式。
4) 伪状态(Pseudo-States)
选择器可以包含伪状态来限制规则只能应用在部件的指定状态上。伪状态出现在选择器之后,用冒号隔开,例如:QPushButton:hover{color:white}这个规则表明当鼠标悬停在一个 QPushButton 部件上时才被应用。
伪状态可以使用感叹号来表示否定,例如要当鼠标没有悬停在一个 QRadioButton 上时才应用规则,那么这个规则可以写为:
QRadioButton:!hover{color:red}
伪状态还可以多个连用,达到逻辑与效果,例如当鼠标悬停在一个被选中的 QCheckBox 部件上时才应用规则,那么这个规则可以写为:
QCheckBox:hover:checked{color:white}
如果有需要,也可以使用逗号来表示逻辑或操作,例如:
QCheckBox:hover,QCheckBox:checked{color:white}
当然,伪状态也可以和子控件联合使用:
QComboBox::drop-down:hover { image: url(dropdown_bright.png) }在 Qt Style Sheets Reference 关键字对应的帮助文档的 List of Pseudo-States 一项中列出了 Qt 支持的所有伪状态。
5) 冲突解决
当几个样式规则对相同的属性指定了不同的值时就会产生冲突。例如:QPushButton#okButton { color: gray } QPushButton { color: red }这样,okButton 的 color 属性便产生了冲突。
解决这个冲突的原则是:特殊的选择器优先。因为 QPushButton#okButton 一般代表一个单一的对象,而不是一个类所有的实例,所以它比 QPushButton 更特殊,那么这时便会使用第一个规则,okButton 的文本颜色为灰色。
相似的,有伪状态比没有伪状态优先。如果两个选择符的特殊性相同,则后面出现的比前面的优先。Qt 样式表使用 CSS2 规范来确定规则的特殊性。
6) 层叠
样式表可以被设置在 QApplication 上、父部件上或者子部件上。部件有效的样式表是通过部件祖先的样式表和 QApplication 上的样式表合并得到的。当发生冲突时,部件自己的样式表优先于任何继承的样式表,同样,父部件的样式表优先于祖先的样式表。
7) 继承
当使用 Qt 样式表时,部件并不会自动从父部件继承字体和颜色设置。例如,一个 QPushButton 包含在一个 QGroupBox 中,这里对 QGroupBox 设置样式表:
qApp->setStyleSheet("QGroupBox { color: red; } ");但没有对 QPushButton 设置样式表。这时,QPushButton 会使用系统颜色,而不会继承 QGroupBox 的颜色。
如果想要 QGroupBox 的颜色设置到其子部件上,可以这样设置样式表:
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
8) 设置QObject属性
从 Qt 4.3 开始,任何可设计的 Q_PROPERTY 都可以使用“qproperty-属性名称”语法来设置样式表。例如:QPushButton
Qt自定义部件外观
1) 盒子模型(The Box Model)
当使用样式表时,每一个部件都看作拥有 4 个同心矩形的盒子,如下图所示:
图 2 盒子模型示意图
这 4 个矩形分别是内容(content)、填衬(padding)、边框(border)和边距(margin)。边距、边框宽度和填衬等属性的默认值都是 0,这样 4 个矩形恰好重合。
可以使用 background-image 属性来为部件指定一个背景。默认 background-image 只在边框以内的区域进行绘制,这个可以使用 background-clip 属性来进行更改。还可以使用 background-repeat 和 background-origin 来控制背景图片的重复方式以及原点。
一个 background-image 无法随着部件的大小来自动缩放,如果想要背景随着部件的大小变化,那就必须使用 border-image。如果同时指定了 background-image 和 border-image,那么 border-image 会绘制在 background-image 之上。
此外,image 属性可以用来在 border-image 之上绘制一个图片。如果使用 image 指定的图片的大小与部件的大小不匹配,那么它不会平铺或者拉伸。图片的对齐方式可以使用 image-position 属性来设置。
2) 自定义部件外观示例
下面我们看一个综合使用样式表的例子。首先向项目目录中添加 3 张图片,再向项目中添加一个 Qt 资源文件,名称为 myresource。
建立完成后,先添加前缀 /images,然后将项目目录中的 3 张图片添加进来,最后按下 Ctrl+S 快捷键进行保存。
完成后进入设计模式,再次打开主界面的“编辑样式表”对话框,先清空以前的代码,再添加如下代码:
/****************主界面背景*******************/ QMainWindow{ }这里可以将光标放到第一个大括号后,然后在“添加资源”的下拉列表中选择 background- image,在弹出的“选择资源”对话框中选择一张背景图片,这样便可以自动添加使用图片的代码。随后更改QPushButton 和 QSlider 的样式代码,最终的代码为:
/****************主界面背景*******************/ QMainWindow{ /*背景图片*/ background-image: url(:/images/bg.png); } /****************按钮部件*******************/ QPushButton{ /*背景色*/ background-color: rgba(100, 225, 100, 30); /*边框样式*/ border-style: outset; /*边框宽度为4像素*/ border-width: 4px; /*边框圆角半径*/ border-radius: 10px; /*边框颜色*/ border-color: rgba(255, 225, 255, 30); /*字体*/ font: bold 14px; /*字体颜色*/ color:rgba(0, 0, 0, 100); /*填衬*/ padding: 6px; } /*鼠标悬停在按钮上时*/ QPushButton:hover{ background-color:rgba(100,255,100, 100); border-color: rgba(255, 225, 255, 200); color:rgba(0, 0, 0, 200); } /*按钮被按下时*/ QPushButton:pressed { background-color:rgba(100,255,100, 200); border-color: rgba(255, 225, 255, 30); border-style: inset; color:rgba(0, 0, 0, 100); } /****************滑块部件*******************/ /*水平滑块的手柄*/ QSlider::handle:horizontal { image: url(:/images/sliderHandle.png); } /*水平滑块手柄以前的部分*/ QSlider::sub-page:horizontal { /*边框图片*/ border-image: url(:/images/slider.png); }下面回到设计模式,将界面上的 pushButton 部件的大小更改为宽 120、高 40,将 horizontalSlider 部件的大小更改为宽 280、高 6。现在运行程序,拖动滑块手柄,然后按下按钮,查看效果。
3) 使用.qss文件
Qt 样式表可以存放在一个以 .qss 为后缀的文件中,这样就可以在程序中通过调用不同的文件来实现不同的界面外观。下面先在前面的程序中添加新文件,模板选择概要分类中的 Empty File,名称为 my.qss。建立完成后,将前面在主界面的“编辑样式表”对话框中的内容全部剪切到这个文件中(注意:要将“编辑样式表”对话框中的内容清空)。然后按下 Ctrl+S 快捷键保存该文件。
在 myresource.qrc 文件上右击,在弹出的快捷菜单中选择“用...打开→资源编辑器”菜单项,打开资源文件。然后添加一个 /qss 前缀(添加这个前缀只是为了将文件区分开),再选择项目目录下新添加的 my.qss 文件。最后按下 Ctrl+S 快捷键保存修改。
下面先打开 mainwindow.h 文件,添加类前置声明:
class QFile;然后添加一个私有对象指针:
QFile *qssFile;转到 mainwindow.cpp 文件中,添加头文件 #include <QFile>,然后在构造函数中添加代码:
qssFile = new QFile(":/qss/my.qss", this); // 只读方式打开该文件 qssFile->open(QFile::ReadOnly); // 读取文件全部内容 QString styleSheet = QString(qssFile->readAll()); // 为QApplication设置样式表 qApp->setStyleSheet(styleSheet); qssFile->close();现在可以运行程序查看效果。可以在帮助中通过 Qt Style Sheets 关键字来查看样式表更多相关内容。在 Qt Style Sheets Examples 关键字对应的文档中列举了很多常用部件的一些样式表应用范例,也可以作为参考。