 QSS 属性选择器)
在 PySide6 的 QSS 属性选择器中所有控件的内置可访问属性即有xxx()方法可以读取的属性都可作为筛选条件不同控件有专属属性也有跨控件通用属性。下面将学习一些常用的部件和属性完整官方文档见https://doc.qt.io/qt-6/stylesheet-reference.html#list-of-sub-controls。一、常见的跨控件通用属性所有控件都支持这类属性是 Qt 控件的基础属性几乎所有控件QWidget 子类都具备可作为通用筛选条件属性名类型说明QSS 匹配示例enabled布尔控件是否启用可交互QWidget[enabledfalse]禁用控件visible布尔控件是否可见QWidget[visibletrue]可见控件focus布尔控件是否获取焦点QLineEdit[focustrue]获焦输入框checked布尔控件是否选中复选框 / 单选框 / 按钮等QCheckBox[checkedtrue]选中复选框windowTitle字符串窗口标题仅顶层窗口QMainWindow[windowTitle主界面]objectName字符串控件唯一标识setObjectName设置QPushButton[objectNamesubmitBtn]minimumWidth整数控件最小宽度QWidget[minimumWidth200]maximumHeight整数控件最大高度QWidget[maximumHeight100]tooltip字符串控件提示文本setToolTip设置QPushButton[tooltip提交表单]示例通用属性筛选/* 禁用的所有控件置灰 */ QWidget[enabledfalse] { color: #999; background-color: #f5f5f5; } /* 获取焦点的输入框高亮边框 */ QLineEdit[focustrue] { border: 2px solid #2196F3; } /* 提示文本包含“删除”的按钮标红 */ QPushButton[tooltip*删除] { color: #f44336; }二、专属属性以QPushButton为例QPushButton 作为高频控件除了flat还有以下专属属性可用于 QSS 筛选属性名类型说明QSS 匹配示例text字符串按钮显示的文字QPushButton[text删除]文字为 “删除”default布尔是否为 “默认按钮”回车触发QPushButton[defaulttrue]默认提交按钮autoDefault布尔是否自动成为默认按钮QPushButton[autoDefaultfalse]checkable布尔按钮是否可选中切换状态QPushButton[checkabletrue]可选中按钮checked布尔可选中按钮的选中状态继承通用属性QPushButton[checkabletrue][checkedtrue]iconSizeQSize图标尺寸需匹配宽高仅支持数值QPushButton[iconSize64,64]图标 64x64shortcut字符串快捷键如CtrlSQPushButton[shortcutCtrlS]示例QPushButton 专属属性筛选/* 默认按钮回车触发强化样式 */ QPushButton[defaulttrue] { background-color: #2196F3; color: white; border-radius: 4px; padding: 10px 20px; } /* 可选中的按钮切换按钮 */ QPushButton[checkabletrue] { background-color: #4CAF50; color: white; } /* 文字为“取消”的按钮灰色样式 */ QPushButton[text取消] { background-color: #9E9E9E; color: white; } /*文字包含“开始”的按钮*/ app.setStyleSheet(QPushButton[text*开始] {background-color: green;}) btn1 QPushButton(开始按钮)注意1. Qt 样式表QSS的属性选择器严格遵循「属性存在 属性值匹配」的逻辑所以要注意属性调用的前提比如checked属性有特殊前提的checked是「可勾选控件checkabletrue」的专属状态属性只有当控件的checkable为true时checked属性才会被 Qt 识别。所以下面的代码是不生效的import sys from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout from PySide6.QtWidgets import QWidget app QApplication(sys.argv) window QWidget() btn1 QPushButton(确定) btn1.setCheckable(True) btn1.clicked.connect(lambda: btn1.setStyleSheet(btn1.styleSheet())) layout QVBoxLayout(window) layout.addWidget(btn1) window.setStyleSheet( QPushButton[checkabletrue] { background-color: #ff0000; color: white; padding: 10px; border: none; border-radius: 5px; } QPushButton[checkedtrue] { background-color: #00ff00; } }) window.resize(300, 200) window.show() sys.exit(app.exec())因为默认QPushButton的checkableFalse那么它就不具备checked这个属性也就无从判断[checkedtrue]这个条件。正确写法是QPushButton[checkabletrue][checkedtrue] { background-color: #00ff00;在[checkabletrue]的QPushButton范围内判断[checkedtrue]。2. 当判断条件的属性发生了变化就要重新加载一次样式表以更新样式。例如import sys from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout from PySide6.QtWidgets import QWidget app QApplication(sys.argv) window QWidget() btn1 QPushButton(确定) btn1.setCheckable(True) # btn1.clicked.connect(lambda :btn1.setStyleSheet()) btn2 QPushButton(确定) btn3 QPushButton(取消) layout QVBoxLayout(window) layout.addWidget(btn1) layout.addWidget(btn2) layout.addWidget(btn3) window.setStyleSheet( QPushButton[checkabletrue] { background-color: #ff0000; color: white; padding: 10px; border: none; border-radius: 5px; } QPushButton[checkabletrue][checkedtrue] { background-color: #00ff00; } }) window.resize(300, 200) window.show() sys.exit(app.exec())运行后发现即使btn1的checked属性已经发生了变化它的背景色仍然没有变化。这是因为虽然btn1的checked属性发生了变化但是它在上一次设置样式表时并不符合“[checkedtrue]”这个条件所以就要在checked属性发生了变化之后再次给它设置样式表这一次它符合“[checkedtrue]”这个条件增加语句btn1.clicked.connect(lambda :btn1.setStyleSheet())这里运行了一次setStyleSheet()重新设置样式表。由于btn1的样式表内容被它的父辈隐含定义了所以这里传递一个空参数即可。比运行一次 “setStyleSheet() 更好的办法是使用btn.style().unpolish(btn)btn.style().polish(btn)来清除样式缓存和重新初始化btn.style().unpolish(btn) btn.style().polish(btn)unpolish(btn)清除控件btn关联的样式缓存如样式表解析结果、原生样式的状态缓存解除样式与控件的绑定polish(btn)重新让样式系统「处理」控件重新解析样式规则包括样式表、原生样式、自定义样式并应用到控件上。完整代码import sys from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton app QApplication(sys.argv) window QWidget() window.resize(300, 100) layout QVBoxLayout(window) btn QPushButton(按钮) btn.setCheckable(True) def btn_clicked(): btn.style().unpolish(btn) btn.style().polish(btn) btn.clicked.connect(btn_clicked) layout.addWidget(btn) window.setStyleSheet( QPushButton[checkedtrue] { background-color: red;} ) window.show() sys.exit(app.exec())当然了最好的办法是用伪状态来取代属性这是最优解QPushButton[checkabletrue]:checked {}全部代码import sys from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout from PySide6.QtWidgets import QWidget app QApplication(sys.argv) window QWidget() btn1 QPushButton(确定) btn1.setCheckable(True) layout QVBoxLayout(window) layout.addWidget(btn1) window.setStyleSheet( QPushButton[checkabletrue] { background-color: #ff0000; color: white; padding: 10px; border: none; border-radius: 5px; } QPushButton[checkabletrue]:checked { background-color: #00ff00; color: black; } }) window.resize(300, 200) window.show() sys.exit(app.exec())还有基于上面讲过的原因不要把QPushButton[checkabletrue]:checked { /*[checkabletrue]必不可少*/写成QPushButton:checked {因为默认的QPushButton是没有checked这个伪状态的。三、常用控件核心属性按控件类型分类不同控件有专属核心属性是 QSS 精细化样式的关键以下整理高频控件的可筛选属性1. QLineEdit输入框属性名类型说明QSS 匹配示例readOnly布尔是否只读QLineEdit[readOnlytrue]placeholderText字符串占位提示文本QLineEdit[placeholderText*手机号]echoMode枚举输入回显模式如密码隐藏QLineEdit[echoModePassword]示例输入框属性筛选import sys from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QLineEdit from PySide6.QtWidgets import QWidget app QApplication(sys.argv) window QWidget() line_edit1 QLineEdit() line_edit1.setReadOnly(True) line_edit2 QLineEdit() line_edit2.setEchoMode(QLineEdit.Password) layout QVBoxLayout(window) layout.addWidget(line_edit1) layout.addWidget(line_edit2) window.setStyleSheet( /* 只读输入框禁用编辑样式 */ QLineEdit[readOnlytrue] { background-color: #f5f5f5; border: 1px solid red; color: #666; } /* 密码输入框自定义样式 */ QLineEdit[echoModePassword] { border: 2px solid green; } } }) window.resize(300, 200) window.show() sys.exit(app.exec())2. QCheckBox/QRadioButton复选框 / 单选框属性名类型说明QSS 匹配示例checked布尔是否选中核心QRadioButton[checkedtrue]tristate布尔是否支持半选状态仅复选框QCheckBox[tristatetrue]indeterminate布尔是否半选状态仅复选框QCheckBox[indeterminatetrue]text字符串提示文字QCheckBox[text*同意]示例复选框状态样式import sys from PySide6.QtCore import Qt from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QLineEdit, QCheckBox from PySide6.QtWidgets import QWidget app QApplication(sys.argv) window QWidget() check_box QCheckBox(三态复选框) check_box.setTristate(True) # 开启三态模式 check_box.setCheckState(Qt.PartiallyChecked) layout QVBoxLayout() layout.addWidget(check_box) window.setLayout(layout) window.setStyleSheet( /*基础复选框样式控制文字与框体间距 */ QCheckBox { font-size: 20px; spacing: 10px; /* 框体和文字的间距避免重叠 */ } /*设置复选框的指示器尺寸*/ QCheckBox::indicator { width: 24px; /* 宽度 */ height: 24px; /* 高度 */ } /* 半选状态的复选框 */ QCheckBox[tristatetrue]::indicator:indeterminate { background-color: red; } /* 选中状态的复选框 */ QCheckBox[tristatetrue]::indicator:checked { background-color: green; } /* 未选中状态的复选框 */ QCheckBox[tristatetrue]::indicator:unchecked { background-color: blue; } ) window.resize(300, 200) window.show() sys.exit(app.exec())3. QComboBox下拉框属性名类型说明QSS 匹配示例editable布尔是否可编辑输入文本QComboBox[editabletrue]currentIndex整数当前选中项索引QComboBox[currentIndex0]默认第一项count整数下拉选项数量QComboBox[count5]选项 5 个QComboBox的子部件子部件名说明备注lineEdit文本编辑框当setEditable(True)才有此编辑框。可通过combobox.lineEdit().setStyleSheet()设置drop_down下拉按钮QComboBox::drop-down { }down-arrow下拉按钮上的箭头图片QComboBox::down-arrow { }示例可编辑下拉框样式from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QComboBox, QLineEdit import sys app QApplication(sys.argv) window QWidget() window.resize(300, 100) layout QVBoxLayout(window) cb QComboBox() cb.addItems([1, 2, 3]) cb.setEditable(True) cb.setStyleSheet(QComboBox { border: 1px solid gray; border-radius: 3px; padding: 1px 18px 1px 3px; font-size: 30px; min-width: 6em; background-color: green; color: blue; } QComboBox::drop-down { width: 30px; background: white; } QComboBox[editabletrue] { background: blue; } QComboBox::down-arrow { image: url(arrow_down1.png); }) # cb.lineEdit().setStyleSheet(background-color:red;) layout.addWidget(cb) window.show() sys.exit(app.exec())QComboBox的linEdit子部件文本编辑框很奇怪并不能通过“QComboBox::子部件”的方式来修改只能用类似cb.lineEdit().setStyleSheet(background-color:red;)或from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QComboBox, QLineEdit import sys app QApplication(sys.argv) window QWidget() window.resize(300, 100) layout QVBoxLayout(window) cb QComboBox() cb.addItems([1, 2, 3]) cb.setEditable(True) line_edit QLineEdit() line_edit.setStyleSheet( QLineEdit { background-color:red; }) cb.setLineEdit(line_edit) layout.addWidget(cb) window.show() sys.exit(app.exec())这样的方法来间接设定。我查找了各种官方文档也没能找到在样式表中修改它的方法。看上去好像QComboBox的QLinEdit部件并不是它的子部件QComboBox像是一个用QLinEdit、下拉按钮、下拉箭头拼凑起来的缝合怪。后记补充设定QComboBox备选条目特性的方法QComboBox QAbstractItemViewQComboBox QAbstractItemView { border: 1px solid hsl(210, 20%, 35%); border-radius: 0; background-color: hsl(210, 40%, 15%); selection-background-color: hsl(210, 50%, 40%); } QComboBox QAbstractItemView:hover { background-color: hsl(210, 40%, 15%); color: hsl(210, 5%, 90%); } QComboBox QAbstractItemView:selected { background: hsl(210, 50%, 40%); color: hsl(210, 20%, 35%); } QComboBox QAbstractItemView:alternate { background: hsl(210, 40%, 15%); } QComboBox QAbstractItemView::item { padding:10px; }4. QSlider滑块属性名类型说明QSS 匹配示例orientation枚举方向0 水平1 垂直QSlider[orientation1]垂直滑块minimum整数最小值QSlider[minimum0]maximum整数最大值QSlider[maximum100]value整数当前值QSlider[value50]前面已经有滑块的学习记录https://blog.csdn.net/xulibo5828/article/details/1560284925. QProgressBar进度条属性名类型说明QSS 匹配示例value整数当前进度值QProgressBar[value100]进度完成minimum/maximum整数最小 / 最大值QProgressBar[maximum100]textVisible布尔是否显示进度文字QProgressBar[textVisiblefalse]下一节详细学习进度条。四、自定义属性扩展无内置属性的场景如果内置属性无法满足筛选需求可通过setProperty()给控件设置自定义属性QSS 同样支持匹配步骤 1设置自定义属性btn QPushButton(危险按钮) # 设置自定义属性typedanger btn.setProperty(type, danger) # 如果是动态修改属性需刷新样式才能生效 btn.style().unpolish(btn) btn.style().polish(btn)步骤 2QSS 匹配自定义属性import sys from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton app QApplication(sys.argv) window QWidget() window.resize(300, 100) layout QVBoxLayout(window) btn QPushButton(危险按钮) # 设置自定义属性typedanger、sizelarge btn.setProperty(type, danger) btn2 QPushButton(启动按钮) btn2.setProperty(func, start) layout.addWidget(btn) layout.addWidget(btn2) window.setStyleSheet( QPushButton[typedanger] { background-color: red;} QPushButton[funcstart] { background-color: green;} ) window.show() sys.exit(app.exec())五、关键注意事项属性值类型匹配布尔值必须写true/false小写不能写True/False或1/0字符串无需加引号如[text删除]而非[text删除]复合类型如 QSize用逗号分隔如[iconSize64,64]。动态属性刷新运行时修改控件属性如btn.setFlat(True)、btn.setProperty(type, success)后需手动刷新样式widget.style().unpolish(widget) # 清除旧样式缓存 widget.style().polish(widget) # 应用新属性的样式 widget.update() # 刷新控件显示优先级规则属性选择器优先级控件类[属性1值1][属性2值2]多属性组合 控件类[属性值] 纯类选择器如QPushButton。六、一个同时拥有两个自定义属性的复杂样式表demoimport sys from PySide6.QtCore import QObject, QTimer, QRegularExpression, Slot from PySide6.QtGui import QRegularExpressionValidator from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout, QLabel ##########################################app.styleSheet APP_STYLE_SHEET f QPushButton {{ background-color: #e1e1e1; font-size: 20px; padding: 8px 16px; border-radius: 4px; border-top: 1px solid #d0d0d0; border-left: 1px solid #d0d0d0; border-right: 1px solid #303030; border-bottom: 1px solid #303030; }} QPushButton:hover{{ background-color: #e5f1fb; border-top: 2px solid #d0d0d0; border-left: 2px solid #d0d0d0; border-right: 2px solid #303030; border-bottom: 2px solid #303030; }} QPushButton:pressed{{ background-color: #cce4f7; border-top: 1px solid #303030; border-left: 1px solid #303030; border-right: 1px solid #d0d0d0; border-bottom: 1px solid #d0d0d0; }} ##########################################QWidget # 闪烁的小部件闪烁颜色由“blink”控制 widget QWidget BLINKING_WIDGET f {widget}[blinktrue] {{ background-color: red; color: white; /*border: 1px solid #dea884;*/ }} ##########################################QPushButton # 绿色按钮颜色由“light”控制 widget QPushButton GREEN_PUSHBUTTON f {widget}[lighttrue] {{ background-color: #4CAF50; color: white; /*border: 1px solid #dea884;*/ }} {widget}[lighttrue]:hover {{ background-color: #3e8e41; }} {widget}[lighttrue]:pressed {{ background-color: #297937; }} {widget}[lightfalse] {{ background-color: #e1e1e1; color: black; border-right: 1px solid #4CAF50; border-bottom: 1px solid #4CAF50; }} {widget}[lightfalse]:hover {{ background-color: #e5f1fb; border-right: 2px solid #4CAF50; border-bottom: 2px solid #4CAF50; }} {widget}[lightfalse]:pressed {{ background-color: #cce4f7; border-right: 1px solid #4CAF50; border-bottom: 1px solid #4CAF50; /*border: 1px solid #4CAF50;*/ }} {widget}:disabled {{ background-color: #A9A9A9; color: 9F9F9F; /*border: 1px solid #808080;*/ }} ##########################################QLabel # 展示标签 widget QLabel SHOW_LABEL f {widget} {{ background - color: #F1F1F1; color: black; font-size: 16px; padding: 8px 16px; border: 1px solid #A0A0A0; border-radius: 4px; }} class UiManager(QObject): def __init__(self, parentNone): UI管理器各种关于UI的功能函数 :param parent: super().__init__(parent) self.blinked_widgets [] # 需要闪烁的所有部件 self.blink_timer QTimer() self.blink_timer.setInterval(1000) self.blink_timer.timeout.connect(self.on_blink_timer_timeout) self.blink_timer.start() self.blink_value True # 设置文字输入的正则公式 def set_validator(self, widget, value): 数字输入的正则函数 light_up^ 表示匹配字符串的开始位置。 light_up-? 表示匹配一个可选的负号-。 light_up\d 表示匹配一个或多个数字字符0-9。 light_up\.? 表示匹配一个可选的小数点.。在正则表达式中. 是一个特殊字符需要用 \ 进行转义因此写作 \.。 light_up\d 表示匹配一个或多个数字字符。 light_up$ 表示匹配字符串的结束位置。 light_up如果希望可以输入负数则正则表达式为^-?\d\.?\d$ light_up如果希望输入非负数则正则表达式为 ^\d\.?\d$ reg QRegularExpression(value) validator QRegularExpressionValidator() validator.setRegularExpression(reg) if isinstance(widget, list): for w in widget: w.setValidator(validator) else: widget.setValidator(validator) # 动态设置属性 def set_property(self, obj, prop, value): if not isinstance(obj, list): # 批量操作 objs [obj] else: objs obj for o in objs: if value 1: value True elif value 0 or value is None: value False o.setProperty(prop, value) # 如果是设置闪烁 if prop blinking: if o not in self.blinked_widgets: self.blinked_widgets.append(o) else: # 刷新显示 o.style().unpolish(o) o.style().polish(o) # 闪烁定时器的超时槽函数 Slot() def on_blink_timer_timeout(self): self.blink_value not self.blink_value # 反转显示 if len(self.blinked_widgets) 0: for widget in self.blinked_widgets: # 去掉不需要闪烁的 if not widget.property(blinking): widget.setProperty(blink, False) widget.style().unpolish(widget) widget.style().polish(widget) self.blinked_widgets.remove(widget) if len(self.blinked_widgets) 0: for widget in self.blinked_widgets: widget.setProperty(blink, self.blink_value) widget.style().unpolish(widget) widget.style().polish(widget) app QApplication(sys.argv) app.setStyleSheet(APP_STYLE_SHEET) um UiManager() widget QWidget() layout QVBoxLayout() widget.setLayout(layout) label QLabel(Hello World) label.setStyleSheet(SHOW_LABEL BLINKING_WIDGET) # 设置为带闪动的展示标签 layout.addWidget(label) um.set_property(label, blinking, True) btn1 QPushButton(Start) btn1.setStyleSheet(GREEN_PUSHBUTTON BLINKING_WIDGET) # 设置为带闪动的绿色灯按钮 btn1.clicked.connect(lambda: um.set_property(btn1, light, True)) btn2 QPushButton(Stop) layout.addWidget(btn1) btn2.clicked.connect(lambda: um.set_property(btn1, light, False)) layout.addWidget(btn2) btn3 QPushButton(toggle Blink) btn3.clicked.connect(lambda: um.set_property([btn1, label], blinking, not btn1.property(blinking))) layout.addWidget(btn3) widget.show() sys.exit(app.exec())总结QSS 属性选择器的核心是「控件的可访问属性」可筛选的属性分为三类通用属性所有控件enabled/focus/objectName等控件专属属性如 QPushButton 的default/checkable、QLineEdit 的readOnly自定义属性通过setProperty扩展。灵活组合这些属性可实现 “精准定位控件 差异化样式”避免为每个控件单独写样式大幅提升 QSS 的复用性和维护性。