样式表旋转框的字体无法调整大小

Posted

技术标签:

【中文标题】样式表旋转框的字体无法调整大小【英文标题】:The font of a stylesheeted spinbox cannot be resized 【发布时间】:2020-10-30 18:57:42 【问题描述】:

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

一种可能的解决方法是保存当前样式表,暂时将其设置为“无”,调整字体大小并恢复样式表,但这听起来既可怕又笨拙。

我正在使用 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"labeln+1", label)

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

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

            sb = QSpinBox(parent=self)
            sb.move(10+150*n, 140)
            sb.setSpecialValueText("QSpinBox")
            setattr(self, f"sbn+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_()

【问题讨论】:

【参考方案1】:

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

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

在经典 CSS 中,当项目的字体和颜色没有明确设置时,它会自动从父项继承。默认情况下,使用 Qt 样式表时,小部件不会自动从其父小部件继承其字体和颜色设置。

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

QSpinBox,与其他小部件(如 QComboBox 和项目视图)一样,是一个复杂小部件,它使用子小部件来显示并与之交互,在这种情况下,它是一个 QLineEdit(可通过 @987654322 访问@)。

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

    在应用程序上设置AA_UseStyleSheetPropagationInWidgetStyles 属性

    QApplication.setAttribute(
        Qt.AA_UseStyleSheetPropagationInWidgetStyles, True)
    

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

    检查小部件是否为 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)
    

    使用样式表设置字体。在您的情况下,您可以检查小部件是否具有样式表并使用模板对其进行更新:

    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)
    

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

【讨论】:

感谢您提供如此完整的答案!解决方案 2 对我来说似乎是最优雅的,因为我可以在我的自动调整大小函数中隐藏细节(​​MRE 只是它们的基本版本)并涵盖所有案例,而不仅仅是旋转框,如果解决方案 1 不适合。 @Guimute 考虑您​​甚至可以尝试使用for child in widget.findChildren(QWidget): child.setFont(font) 检查子小部件,这将确保为其他复杂小部件设置字体,例如组合框的弹出窗口或项目视图的标题.

以上是关于样式表旋转框的字体无法调整大小的主要内容,如果未能解决你的问题,请参考以下文章

Confluence 6 中样式化字体

如何调整chm文字字体大小

使用 Ctrl 键和鼠标滚动调整 Emacs 字体大小

在高 DPI 设置下调整 RichTextBox 字体大小

iOS 无法在设备旋转时自动调整子视图大小

Mac ps如何调整文字大小与位置