样式表在 PyQt 中不能正常工作

Stylesheet does not work properly in PyQt

我正在尝试使用 PyQt 开发 uild 应用程序,因此我决定首先使用 qt Designer 开发 UI。我想为我的元素设置样式,所以我使用样式表来指定我需要的样式。在 qt Designer 中制作 UI 后,我使用预览按钮查看是否一切正常,一切都按预期工作。然后,我使用 pyuic5 将 UI 文件转换为 python 版本。现在,几乎一切正常,但 SOME 样式表无法正常工作。例如,我为 QComboBox 使用了样式表,除了样式表的 QComboBox QAbstractItemView 部分之外,一切正常。怎么了?一半代码有效,另一半无效。如果您需要,这里是样式表:

QComboBox{
    color: #F5F3F4;
    border: 2px solid #E5383B;
    border-radius: 15px;
    background-color: #BA181B;
    padding: 2px;
    padding-left: 5px;
}

QComboBox::drop-down {
    border: 0px;
    width: 0px;
}

QComboBox QAbstractItemView {
    border: 2px solid #E5383B;
    selection-background-color: #A4161A;
    color: #F5F3F4;
    background-color: #BA181B;
    border-radius: 5px;
}

只有最后一部分在python应用程序中不起作用,但在qt Designer预览模式下完美运行。

编辑:

我打算做什么(qt Designer 也显示)

Python 输出什么

app.setStyle("fusion") 的作用(组合框打开时)

.ui 文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QComboBox" name="comboBox">
    <property name="geometry">
     <rect>
      <x>160</x>
      <y>140</y>
      <width>69</width>
      <height>22</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">QComboBox{
    color: #F5F3F4;
    border: 2px solid #E5383B;
    border-radius: 15px;
    background-color: #BA181B;
    padding: 2px;
    padding-left: 5px;
}

QComboBox::drop-down {
    border: 0px;
    width: 0px;
}

QComboBox QAbstractItemView {
    border: 2px solid #E5383B;
    selection-background-color: #A4161A;
    color: #F5F3F4;
    background-color: #BA181B;
    border-radius: 5px;
}</string>
    </property>
    <item>
     <property name="text">
      <string>New Item</string>
     </property>
    </item>
    <item>
     <property name="text">
      <string>New Item 2</string>
     </property>
    </item>
   </widget>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

然后,我使用

将 .ui 文件转换为其 .py 版本
pyuic5 ui.py ui.ui

python 文件:

from ui import UI
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow, qApp, QDockWidget, QFileDialog
from PyQt5 import QtWidgets, QtGui

import sys

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.ui = UI()
        self.ui.setupUi(self)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("fusion")
    app.setWindowIcon(QtGui.QIcon('gallery/icon.jpg'))
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

存在一些与样式sheet的传播相关的问题,特别是对于使用滚动区域(或从它们继承)的复杂小部件。

不幸的是,由于样式传播和样式管理的复杂性sheet,很难找到问题的确切根源,并且存在一些关于此问题的 Qt 错误报告。

首先,最好有一个单一的和集中的样式sheet:每当你必须修改一个可能在很多小部件之间共享的属性时,你没有修改 每个 小部件的样式 sheet。缺点是如果你有许多相同 class 类型的不同样式的小部件,你需要更好地使用选择器(# 选择器是最好的选择,因为它使用小部件的对象名称来标识它,并且对象名称通常是唯一的);阅读更多关于 Qt stylesheet selectors.

如果您的程序只有一个主程序 window(其他所有内容都是它的子项,包括对话框),您可以在 window 上设置样式sheet,否则最好在 QApplication 上设置样式sheet。

然后,每当出现这些问题时,一个可能的解决方案是在显示小部件后立即再次设置样式sheet。对于简单的情况,您可以尝试以下方法:

class MainWindow(QMainWindow):
    <b>shown = False</b>
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.ui = UI()
        self.ui.setupUi(self)

    def showEvent(self, event):
        super().showEvent(event)
        if not self.shown:
            self.shown = True
            self.ui.setStyleSheet(self.ui.styleSheet())

与 Qt 忽略与当前值相同的新值的其他属性不同,每次调用 setStyleSheet() 都会导致整个小部件(及其子项)重新抛光 他们,即使样式 sheet 为空。

最后,最好避免使用过于通用的样式sheet,因为它们可能会导致意外行为(我知道这不是你的情况,但这是一个应该始终牢记的重要方面) .
因此,应避免或至少谨慎使用以下内容:

setStyleSheet('color: somecolor; border: someborder')

setStyleSheet('QWidget { color: somecolor; border: someborder; }')

setStyleSheet('* { color: somecolor; border: someborder; }')