样式表旋转框的字体不能调整大小

The font of a stylesheeted spinbox cannot be resized

如果应用了样式表,修改 QSpinBox 的字体大小没有任何效果,而我测试的所有其他小部件 类 都可以正确调整大小,而不管它们的样式表如何。 QSpinBox没有样式表的元素也会正确调整大小。请注意,所有小部件的 .font().pointSize() 都是相等的,所以我认为这只是一个显示问题。

一种可能的解决方法是保存当前样式表,将其暂时设置为 None,调整字体大小并恢复样式表,但这听起来很糟糕而且很老套。

我正在使用 Python 3.7.4 和 PyQt5 5.12.2。

这是我的 MRE 的样子:

下面是使用的代码:

# -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QLabel, QLineEdit, QPushButton, QSpinBox, QMainWindow
import sys

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()

        # Setup widgets.
        self.widgets = []

        for n in range(2):
            label = QLabel(parent=self)
            label.move(10+150*n, 20)
            label.setText("QLabel")
            setattr(self, f"label{n+1}", label)

            pb = QPushButton(parent=self)
            pb.move(10+150*n, 60)
            pb.setText("QPushButton")
            setattr(self, f"pb{n+1}", pb)

            le = QLineEdit(parent=self)
            le.move(10+150*n, 100)
            le.setText("QLineEdit")
            setattr(self, f"le{n+1}", le)

            sb = QSpinBox(parent=self)
            sb.move(10+150*n, 140)
            sb.setSpecialValueText("QSpinBox")
            setattr(self, f"sb{n+1}", sb)

            for widget in (label, pb, le, sb):
                self.widgets.append(widget)

        # Take note of the initial window size.
        self.initial_size = (self.width(), self.height(), 30)
        self.resize(300, 200)

        # Paint the right-hand side widgets in red.
        for widget in self.widgets[int(len(self.widgets)/2):]:
            class_name = widget.__class__.__name__ # QLabel, QPushButton, QSpinBox.
            widget.setStyleSheet(class_name + "{background-color: red}")



    def resizeEvent(self, event):
        """Adjust the fontsize of all the widgets upon resizing the main window."""

        # Calculate a scale factor by comparing current and initial size.
        w0, h0, f0 = self.initial_size
        w, h = self.width(), self.height()
        scale = min(w/w0, h/h0)

        # Apply the scale factor to each widget font.
        for widget in self.widgets:
            font = widget.font()
            font.setPointSize(scale * f0)
            widget.setFont(font)

        # Check that all fontsizes are identical.
        assert len(set(widget.font().pointSize() for widget in self.widgets)) == 1



if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setAttribute(Qt.AA_DisableHighDpiScaling) # Because it's irrelevant here.
    app.setQuitOnLastWindowClosed(True)
    window = MainWindow()
    window.show()
    app.exec_()

只要将样式表设置为小部件,Qt 就会自动禁用该小部件的调色板和字体传播。这意味着所有 child widget 都不会收到来自父级的有关字体(和调色板)更改的通知。

这在样式表语法的 inheritance 章节中有解释:

In classic CSS, when font and color of an item is not explicitly set, it gets automatically inherited from the parent. By default, when using Qt Style Sheets, a widget does not automatically inherit its font and color setting from its parent widget.

注意上面明显是指使用setFont()设置的字体和使用setPalette()设置的颜色。如果您在样式表 中设置字体或颜色 这些 属性的传播将根据 级联按预期工作 样式表的性质。

QSpinBox 与 QComboBox 和项目视图等其他小部件一样,是一个 复杂 小部件,它使用子小部件来显示它并与之交互,在本例中它是一个 QLineEdit (可通过 lineEdit() 访问)。

为了解决您的问题,有多种方法可用:

  1. 在应用程序上设置 AA_UseStyleSheetPropagationInWidgetStyles 属性 :

    QApplication.setAttribute(
        Qt.AA_UseStyleSheetPropagationInWidgetStyles, True)
    

    这显然有副作用,传播将适用于应用程序的 所有 小部件,由您决定是否合适。
    注意:此属性已从 Qt 5.7 引入。

  2. 检查小部件是否为 QSpinBox 并为其行编辑设置字体:

    for widget in self.widgets:
        font = widget.font()
        font.setPointSize(scale * f0)
        if isinstance(widget, QSpinBox):
            widget.lineEdit().setFont(font)
        else:
            widget.setFont(font)
    
  3. 使用样式表设置字体。在你的情况下,你可以检查小部件是否有样式表并使用模板更新它:

    baseStyleSheet = '''
    {} {{
        background-color: red;
        font-size: {}px;
    }}
    '''
    
    # ...
        def resizeEvent(self, event):
            w0, h0, f0 = self.initial_size
            w, h = self.width(), self.height()
            scale = min(w/w0, h/h0)
            font_size = scale * f0
    
            for widget in self.widgets:
                if widget.styleSheet():
                    widget.setStyleSheet(baseStyleSheet.format(
                        widget.__class__.__name__, font_size))
                else:
                    font = widget.font()
                    font.setPointSize(font_size)
                    widget.setFont(font)
    

显然,以上仅适用于仅设置简单属性的特定情况。