Моя текущая реализация использует гибридный подход QProxyStyle + QApplication.setStyleSheet(...)
Эта текущая реализация работает очень хорошо для небольших/простых приложений с примерно Около 15 различных виджетов (таблицы, списки, деревья, поля ввода, метки, флажки, ползунки), но для более крупных/сложных приложений пользовательский интерфейс замораживается на долгое время, прежде чем вы увидите масштабированное содержимое.
Есть ли более быстрый и надежный способ сделать это?
Любые советы будут очень признательны.
Окружающая среда:
- ОС: Windows 11
- Python: 3.11
- PySide6: 6.10.0
- Унаследованный стиль прокси
class ScaledStyle(QProxyStyle):
def __init__(self, baseStyle: QStyle, scale: int = 1):
super().__init__(baseStyle)
self._scale: float = scale
self._cachedMetrics: dict[QProxyStyle.PixelMetric, int] = {}
def setScale(self, scale: float):
self._scale: float = scale
self._cachedMetrics.clear()
def pixelMetric(self, metric, option=None, widget=None):
value = super().pixelMetric(metric, option, widget)
# limit the scaling to toolbars/buttons
# is it wise to scale everything?
if metric in (
QStyle.PixelMetric.PM_SmallIconSize,
QStyle.PixelMetric.PM_LargeIconSize,
QStyle.PixelMetric.PM_ToolBarIconSize,
QStyle.PixelMetric.PM_ButtonIconSize,
):
# clamp the scaling to be at least 1
return max(1, int(value * self._scale))
return value
- менеджер масштабирования
import PySide6.QtCore as qtc
from scaled_style import ScaledStyle
class GUIScalingManager(qtc.QObject):
scaleChanged = qtc.Signal(float)
def __init__(self, app: qtw.QApplication, parent=None) -> None:
super().__init__(parent=parent)
self.__app: qtw.QApplication = app
self.__baseScale = 1.0
self.__scale = 1.0
self.__scaleLB = 0.8
self.__scaleUB = 2.0
self.__scaleStep = 0.2
self.__defaultFontSize = 12.0
self.__scaledStyle: ScaledStyle = ScaledStyle(self.__app.style())
self.__app.setStyle(self.__scaledStyle)
# throttle the scaler to approx 30 frames
self.__scaleTimer = qtc.QTimer()
self.__scaleTimer.setSingleShot(True)
self.__scaleTimer.timeout.connect(self.__applyScale)
self.__scaleTimer.setInterval(32)
def setScale(self, scale: float) -> None:
self.__scale = self.__clampToScaleRange(scale)
self.applyScale()
self.scaleChanged.emit(self.__scale)
def __applyScale(self) -> None:
if not isinstance(self.__app, qtw.QApplication):
return
self.__scaledStyle.setScale(self.__scale)
for widget in self.__app.topLevelWidgets():
widget.setUpdatesEnabled(False)
self.__app.setStyleSheet(
f"""
QWidget{{
font-size: {self.__defaultFontSize * self.__scale}px;
}}
"""
)
for widget in self.__app.topLevelWidgets():
widget.setUpdatesEnabled(True)
widget.updateGeometry()
widget.update()
def applyScale(self) -> None:
self.__scaleTimer.start()
def __clampToScaleRange(self, s: float) -> float:
return max(self.__scaleLB, min(s, self.__scaleUB))
def scaleUp(self):
s = self.__clampToScaleRange(self.__scale + self.__scaleStep)
self.setScale(s)
def scaleDown(self):
s = self.__clampToScaleRange(self.__scale - self.__scaleStep)
self.setScale(s)