25. 样式表
一、样式表
为了美化窗口或控件的外观,可以通过窗口或控件的调色板给窗口或控件按照角色和分组设置颜色,还可以对窗口或控件的每个部分进行更细致的控制,这涉及窗口或控件的样式表(Qt style sheets, QSS),它是从 HTML 的层叠样式表(cascading style sheets, CSS)演化而来的。样式表由固定格式的文本构成,用窗口或控件的 setStyleSheet(styleSheet:str) 方法设置样式,其中参数 styleSheet 是样式格式符。
定义样式表的一般规则是用 "样式属性:值" 的形式定义样式属性的值,多个样式的 "样式属性:值" 对之间用分号 ; 隔开。如果是对某一类控件进行设置,需要先说明控件的类,然后后面跟一对 {},把 "样式属性:值" 放到 {} 中。
setStyleSheet("QLabel{font:48px '华文行楷'; color:#CCCCFF; background-color:rgb(153, 204, 255)}")
我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源 下载。
pip install pyside6 -i https://pypi.tuna.tsinghua.edu.cn/simple
国内常用的 pip 下载源列表:
- 阿里云 https://mirrors.aliyun.com/pypi/simple
- 豆瓣 http://pypi.doubanio.com/simple
- 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
- 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple
新建一个 ui.py 文件,用来存放 UI 相关的代码。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
self.label = QLabel(window) # 2.创建一个标签
self.label.move(10, 10) # 3.设置标签的位置
self.label.setText("这是一个标签") # 4.设置标签的文本
# 5.设置控件的样式
window.setStyleSheet("QLabel{font:48px '华文行楷'; color:#CCCCFF; background-color:rgb(153, 204, 255)}")
新建一个 widget.py 文件,用来存放业务逻辑相关的代码。
import sys
from PySide6.QtWidgets import QApplication, QWidget
from ui import MyUi
class MyWidget(QWidget):
def __init__(self):
super().__init__() # 1.调用父类Qwidget类的__init__()方法
self.__ui = MyUi()
self.__ui.setup_ui(self) # 2.初始化页面
if __name__ == "__main__":
app = QApplication(sys.argv) # 1.创建一个QApplication类的实例
window = MyWidget() # 2.创建一个窗口
window.show() # 3.显示窗口
sys.exit(app.exec()) # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
我们还可以把有关样式设置的代码放置到一个单独的文件中,然后在运行时读取该文件,然后应用该样式表。我们新建一个 style.qss 文件,用来存放样式表相关的代码。
QLabel {
font: 48px '华文行楷';
color: #CCCCFF;
background-color: rgb(153, 204, 255)
}
修改 ui.py 文件,删除设置控件样式的代码。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
self.label = QLabel(window) # 2.创建一个标签
self.label.move(10, 10) # 3.设置标签的位置
self.label.setText("这是一个标签") # 4.设置标签的文本
修改 widget.py 文件,在创建 QApplication 应用实例后,读取样式表文件中的内容,并设置控件样式。
import sys
from PySide6.QtWidgets import QApplication, QWidget
from ui import MyUi
class MyWidget(QWidget):
def __init__(self):
super().__init__() # 1.调用父类Qwidget类的__init__()方法
self.__ui = MyUi()
self.__ui.setup_ui(self) # 2.初始化页面
if __name__ == "__main__":
app = QApplication(sys.argv) # 1.创建一个QApplication类的实例
with open("style.qss", "r", encoding="utf-8") as f: # 2.打开样式表文件
style = f.read() # 3.读取样式表
app.setStyleSheet(style) # 4.设置样式表
window = MyWidget() # 5.创建一个窗口
window.show() # 6.显示窗口
sys.exit(app.exec()) # 7.进入程序的主循环并通过exit()函数确保主循环安全结束
二、选择器
样式表除了类名、对象名和属性名外,一般不区分大小写。样式表由 选择器(selector)和 声明(declaration)两部分构成,选择器用于选择某种类型或多个类型的控件,声明是要设置的属性和属性的值。
选择器的使用方法如下所示:
| 选择器 | 说明 |
|---|---|
| * | 全局选择器,选择所有控件 |
| 类名 | 类型选择器,匹配所有的该类以及子类的实例 |
| 类名[属性名="属性值"] | 属性选择器,匹配该该属性名等于属性值的类的实例,属性可以是自定义的 |
| #对象名称 | ID 选择器,匹配指定对象名称的实例,这里的对象名称是通过 setObjectName() 方法设置的 |
| .类名 | 匹配指定类的所有实例,不包含子类 |
| 父控件类名 子控件类名 | 后代选择器,匹配父控件中直接或间接包含的所有子控件 |
| 父控件类名 > 子控件类名 | 子选择器,匹配父控件中直接包含的所有子控件 |
我们修改 ui.py 文件的内容。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QTextEdit
from PySide6.QtWidgets import QVBoxLayout
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
layout = QVBoxLayout(window) # 2.创建一个垂直布局,并设置为窗口对象的布局
self.label1 = QLabel(window) # 3.创建一个标签,并添加到垂直布局中
self.label1.setObjectName("label1") # 4.设置标签的objectName
self.label1.setText("这是一个标签") # 5.设置标签的文本
layout.addWidget(self.label1)
self.label2 = QLabel(window)
self.label2.setText("这是一个标签")
layout.addWidget(self.label2)
self.label3 = QLabel(window)
self.label3.setText("这是一个标签")
layout.addWidget(self.label3)
self.textEdit = QTextEdit(window)
layout.addWidget(self.textEdit)
修改 style.qss 文件的内容。
* {
font: 48px "华文行楷";
}
QLabel {
color: #FFCCCC;
background-color: #99CCFF;
}
#label1 {
color: #FFFF99;
background-color: #CCFF99;
}
QTextEdit {
color: #66CCFF;
background-color: pink;
}
三、子控件
一些复合型控件,例如 QSpinBox,由 QLineEdit 、向上的箭头 和 向下的箭头 构成,向上的箭头和向下的箭头可以称为 子控件。对子控件的引用是在控件和子控件之间用两个连续的冒号 :: 隔开。例如:QSpinBox 控件的向上调节按钮控件和向下调节按钮控件可以分别通过 ::up-button 和 ::down-button 获取到。
| 子控件名 | 说明 |
|---|---|
| groove | QSlider 的凹槽 |
| handle | QScrollBar、QSplitter、QSlider 的手柄或滑块 |
| corner | QAbstractScrollArea 中两个滚动条之间的角落 |
| add-line | QScrollBar 增加行的按钮,即按下该按钮滚动条增加一行 |
| sub-line | QScrollBar 减少行的按钮,即按下该按钮滚动条减少一行 |
| add-page | QScrollBar 在手柄(滑块)和增加行之间的区域 |
| sub-page | QScrollBar 在手柄(滑块)和减少行之间的区域 |
| up-arrow | QHeaderView(排序指示器)、QScrollBar、QSpinBox 的向上箭头 |
| down-arrow | QComboBox、QHeaderView(排序指示器)、QScrollBar、QSpinBox 的向下箭头 |
| left-arrow | QScrollBar 的左箭头 |
| right-arrow | QMenu 或 QScrollBar 的右箭头 |
| up-button | QSpinBox 的向上按钮 |
| down-button | QScrollBar 或 QSpinBox 的向下按钮 |
| branch | QTreeView 的分支指示符 |
| section | QHeaderView 的分支指示符 |
| text | QAbstractItemView 的文本 |
| chunk | QPorgressBar 的进度块 |
| drop-down | QComboBox 的下拉按钮 |
| indicator | QAbstractItem、QCheckBox、QRadioButton、QMenu(可被选中的)、QGroupBox(可被选中的)指示器 |
| pane | QTabWidget 的面板(边框) |
| left-cornet | QTabWidget 的左角落,可用于控件 QTabWidgetr 中左角落控件的位置 |
| right-cornet | QTabWidget 的右角落,可用于控件 QTabWidgetr 中右角落控件的位置 |
| tab | QTabBar 或 QToolBox 的选项卡 |
| tab-bar | QTabWidget 的选项卡栏,仅用于控制 QTabBar 在 QTabWidget 中的位置 |
| tear | QTabBar 的可分离指示器 |
| close-button | QTabBar 选项卡或 QDockWidget 上的关闭按钮 |
| float-button | QDockWidget 的浮动按钮 |
| title | QDockWidget 或 QGroupBox 的标题 |
| scroller | QMenu 或 QTarBar 的滚动条 |
| separator | QMenu 或 QMainWindow 中的分隔符 |
| tearoff | QMenu 的可分离指示器 |
| item | QAbstractItemView、QMenuBar、QMenu、QStatusBar 中的一个项 |
| icon | QAbstractItemView 或 QMenu 的图标 |
| menu-arrow | 带有菜单的 QToolButton 的箭头 |
| menu-button | QToolButton 的菜单按钮 |
| menu-indicator | QPushButton 的菜单指示器 |
修改 ui.py 文件的内容。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox
from PySide6.QtWidgets import QFormLayout
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
layout = QFormLayout(window) # 2.创建一个表单布局
self.name_lineEdit = QLineEdit() # 3.创建一个QLineEdit对象
self.name_lineEdit.setPlaceholderText("请输入用户名") # 4.设置提示文本
layout.addRow("姓名", self.name_lineEdit) # 5.将QLineEdit对象添加到表单布局中
self.gender_comboBox = QComboBox()
self.gender_comboBox.addItems(["保密", "男", "女"])
layout.addRow("性别", self.gender_comboBox)
self.age_spinBox = QSpinBox(minimum=0, maximum=300)
layout.addRow("年龄", self.age_spinBox)
self.score_doubleSpinBox = QDoubleSpinBox(minimum=0, maximum=100)
layout.addRow("分数", self.score_doubleSpinBox)
修改 style.qss 文件的内容。
* {
font: 32px "华文行楷";
}
QComboBox::down-arrow {
border-image: url(assets/images/1.ico);
}
QSpinBox::up-arrow {
background-color: #99CCFF;
}
QSpinBox::down-arrow {
background-color: #9933FF;
}
QDoubleSpinBox::up-arrow {
background-color: #FFCCCC;
}
QDoubleSpinBox::down-arrow {
background-color: #CCCCFF;
}
四、伪状态
控件会根据用户的不同操作呈现出不同的状态,这些状态也被称为 “伪状态”。一个控件有多种状态,例如 活跃(active)、激活(enabled)、失效(disabled)、鼠标悬停(hover)、选中(checked)、未选中(unchecked) 和 可编辑(editable)等,根据控件所处的状态,可以给控件设置不同的外观。
样式表的格式字符串中,控件与状态之间用冒号 : 隔开,例如 QPushButton:active{...} 设置激活时的外观;可以同时对多个状态进行设置,例如 QPushButton:active:hover{...} 设置激活或者光标悬停时的外观;可以在状态前加 !,表示相反的状态。
| 状态的状态 | 说明 |
|---|---|
| active | 控件处于激活状态 |
| foucus | 该项具有输入焦点 |
| default | 该项是默认值 |
| enabled | 该控件已启动 |
| disabled | 控件已失效 |
| hover | 光标悬停在该控件上 |
| pressed | 使用鼠标按下该控件 |
| checked | 该控件被选中 |
| unchecked | 该控件未被选中 |
| on | 适用于处于开启状态的控件 |
| off | 使用处于关闭关闭状态的控件 |
| open | 该控件处于打开状态 |
| closed | 该控件处于关闭状态 |
| closable | 该控件可被关闭 |
| editable | QComboBox 是可编辑的 |
| read-only | 该控件为只读 |
| only-one | 该控件是唯一的 |
| no-frame | 该控件没有边框 |
| flat | 该控件是平的 |
| floatable | 该控件是可浮动的 |
| movable | 该控件可移动 |
| top | 该控件位于顶部 |
| buttom | 该控件位于底部 |
| left | 该控件位于左侧 |
| right | 该控件处于右侧 |
| middle | 该控件位于中间 |
| horizontal | 该控件具有水平方向 |
| vertical | 该控件具有垂直方向 |
| first | 该控件是第一个 |
| last | 该控件是最后一个 |
| indeterminate | 该控件具有不确定状态 |
| exclusive | 该控件是排它项目组的一部分 |
| non-exclusive | 该控件是非排它项目组的一部分 |
| minimized | 该控件是最小的 |
| maximized | 该控件是最大化的 |
| selected | 该控件被选择 |
| previous-selected | 上一控件被选择 |
| next-selected | 下一控件被选择 |
| window | 控件是一个窗口,即顶级控件 |
| has-children | 该控件具有孩子 |
| has-siblings | 该控件具有兄弟姐妹(即同级的控件) |
| alternate | 当 QAbstractItemView.alternatingRowColors() 被设置为 true 时,为每个交替行设置此状态,以绘制 QAbstractItemView 的行 |
修改 ui.py 文件的内容。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLineEdit, QPushButton
from PySide6.QtWidgets import QGridLayout, QFormLayout
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
grid_layout = QGridLayout(window) # 2.创建一个栅格布局
form_layout = QFormLayout() # 3.创建一个表单布局
grid_layout.addLayout(form_layout, 0, 0, 1, 3) # 4.将表单布局添加到栅格布局中
self.name_lineEdit = QLineEdit() # 5.创建单行文本编辑控件
self.name_lineEdit.setPlaceholderText("请输入用户") # 6.设置单行文本编辑控件的提示文本
form_layout.addRow("用户名", self.name_lineEdit) # 7.将标签和单行文本编辑控件添加到表单布局中
self.password_lineEdit = QLineEdit()
self.password_lineEdit.setEchoMode(QLineEdit.EchoMode.Password)
self.password_lineEdit.setPlaceholderText("请输入密码")
form_layout.addRow("密码", self.password_lineEdit)
self.reset_button = QPushButton("重置")
grid_layout.addWidget(self.reset_button, 1, 0)
self.ok_button = QPushButton("确定")
grid_layout.addWidget(self.ok_button, 1, 2)
修改 style.qss 文件的内容。
* {
font: 32px "华文行楷";
}
QLineEdit:focus {
background-color: #CCCCFF;
}
QPushButton:pressed {
background-color: #FF6666;
}
五、样式的属性
控件有背景色、前景色及选中状态时的背景色和前景色,可以对这些颜色分别进行设置。
| 颜色属性名称 | 说明 |
|---|---|
| background | 设置背景的简写方法,相当于指定 background-color、background-image、background-repeat、background-position |
| background-color | 控件的背景色 |
| background-image | 控件的背景图像 |
| background-repeat | 如何使用背景图像填充背景区域,若未指定 background-origin 属性则在两个方向重复背景图像 |
| background-position | 背景图像在 background-origin 矩形内的位置,默认未 topleft |
| background-attachment | 确定 QAbstractScrollArea 中的 background-image 是相对与视图滚动还是固定,默认值为 scroll |
| background-clip | 控制绘制背景的矩形,此属性指定 background-color 和 background-image 的裁剪矩形。此属性默认值为 border(即边框矩形) |
| background-origin | 控件背景的原点矩形,通常与 background-position 和 background-image 一起使用,默认为 padding(即边框矩形) |
| color | 渲染文本的颜色,所有遵守 QWidget.palette 的控件都支持此属性 |
| selection-color | 所选文本或项的前景色,默认为调色板的 QPalette.HighlightedText 角色的值 |
| selection-background-color | 所选文本或项的背景色,默认为调色板的 QPalette.Highlight 角色的值 |
修改 ui.py 文件的内容。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QTextEdit
from PySide6.QtWidgets import QVBoxLayout
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
layout = QVBoxLayout(window) # 2.创建一个垂直布局
self.textEdit = QTextEdit() # 3.创建一个多行文本编辑控件
layout.addWidget(self.textEdit) # 4.将多行文本编辑控件添加到布局中
self.textEdit.setText("这是多行文本编辑控件") # 5.设置多行文本编辑控件的文本
修改 style.qss 文件的内容。
QTextEdit {
font: 32px "华文行楷";
color: #99CCFF;
background-image: url(assets/images/1.jpg);
selection-color: #FF99CC;
selection-background-color: #FFFF66;
}
六、盒子模型
大多数控件都是长方形的,一个长方形控件由 Content、Padding、Border 和 Margin 4 部分构成,每个部分都是矩形。Content 矩形是 除掉边距、边框和填充之后的部分,默认情况下,边距、边框和填充的距离都为 0,因此这 4 个矩形是重合的。可以用样式表分别设置这四个矩形之间的距离、边框的颜色。

Content 是 输入内容的区域,可以设置 Content 区域宽度和高度的最大值和最小值,属性名称分别为 max-width、max-height、min-width 和 min-height。
对于 Padding 区域,用 padding 属性可以分别 设置 Padding 与 Content 在上、右、下和左方向的距离,也可用 padding-top、padding-right、padding-bottom 和 padding-left 属性分别设置距离。
Border 区域可以设置的属性比较多,如下所示。
| 属性名称 | 说明 |
|---|---|
| border | 设置边框的简写方法,相当于指定 border-color、border-style 和 border-width |
| border-top | 设置控件顶部边框的简写方法,相当于指定 border-top-color、border-top-style 和 border-top-width |
| border-right | 设置控件右边框的简写方法,相当于指定 border-right-color、border-right-style 和 border-right-width |
| border-bottom | 设置控件底部边框的简写方法,相当于指定 border-bottom-color、border-bottom-style 和 border-bottom-width |
| border-left | 设置控件左边框的简写方法,相当于指定 border-left-color、border-left-style 和 border-left-width |
| border-color | 边框边界的颜色,相当于指定 border-top-color、border-right-color、border-bottom-color 和 border-left-color,默认值为控件的前景色 |
| border-top-color | 边框顶部边界线的颜色 |
| border-right-color | 边框右边界线的颜色 |
| border-bottom-color | 边框底部边界线的颜色 |
| border-left-color | 边框左边界线的颜色 |
| border-radius | 边框角落的圆角半径,相当于指定 border-top-left-radius、border-top-right-radius、border-bottom-right-radius 和 bordedr-bottom-left-radius,默认值为 0 |
| border-top-left-radius | 边框左上角圆角的半径 |
| border-top-right-radius | 边框右上角圆角的半径 |
| border-bottom-right-radius | 边框右下角圆角的半径 |
| bordedr-bottom-left-radius | 边框左下角圆角的半径 |
| border-style | 边框边界线的样式(实线 solid、虚线 dashed、点划线 dotted等),默认为 None |
| border-top-style | 边框顶部边界线的样式 |
| border-right-style | 边框右侧边界线的样式 |
| border-bottom-style | 边框底部边界线的样式 |
| border-left-style | 边框左侧边界线的样式 |
| border-width | 边框的宽度,相当于指定 border-top-width、border-right-width、border-bottom-width 和 border-left-width |
| border-top-width | 边框顶部边界线的宽度 |
| border-right-width | 边框右侧边界线的宽度 |
| border-bottom-width | 边框底部边界线的宽度 |
| border-left-width | 边框左侧边界线的宽度 |
| border-image | 填充边框的图像,该图像被分割成 9 个部分,并在必要时适当的拉伸 |
对于 Margin 区域可以 设置页边距。margin 属性 设置控件的边距,等效于指定 margin-top、margin-right、margin-bottom、margin-left,默认为 0,margin-top、margin-right、margin-bottom、margin-left 分别 设置控件的上、右、下和左侧的边距。
修改 ui.py 文件的内容。
from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel
class MyUi:
def setup_ui(self, window:QWidget):
window.resize(800, 600) # 1.设置窗口对象大小
self.label = QLabel(window) # 2.创建一个标签控件
self.label.setText("这是一个标签控件") # 3.设置标签控件的文本
修改 style.qss 文件的内容。
QLabel {
font: 32px "华文行楷";
color: #99CCFF;
background-color: #FFFF66;
min-width: 300px;
min-height: 100px;
max-width: 300px;
max-height: 100px;
padding: 10px;
border-style: dashed;
border-color: #FFCC99;
border-width: 5px;
border-radius: 5px;
margin: 10px;
}

浙公网安备 33010602011771号