样式表旋转框的字体无法调整大小
Posted
技术标签:
【中文标题】样式表旋转框的字体无法调整大小【英文标题】:The font of a stylesheeted spinbox cannot be resized 【发布时间】:2020-10-30 18:57:42 【问题描述】:如果应用了样式表,则修改QSpinBox
的字体大小无效,而我测试的所有其他小部件类无论其样式表如何都已正确调整大小。没有样式表的QSpinBox
es 也会正确调整大小。请注意,所有小部件的 .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)
检查子小部件,这将确保为其他复杂小部件设置字体,例如组合框的弹出窗口或项目视图的标题.以上是关于样式表旋转框的字体无法调整大小的主要内容,如果未能解决你的问题,请参考以下文章