Как масштабировать компоненты пользовательского интерфейса, такие как размер шрифта и размер значков, для приложения PySPython

Программы на Python
Anonymous
Как масштабировать компоненты пользовательского интерфейса, такие как размер шрифта и размер значков, для приложения PyS

Сообщение Anonymous »

У меня есть большое приложение, которое использует множество компонентов графического интерфейса (таблицы, списки, деревья, поля ввода, метки, флажки, ползунки и т. д.). В целях доступности я хотел бы реализовать функцию масштабирования, аналогичную той, которую использует VS Code или JetBrains, при которой компоненты/содержимое пользовательского интерфейса масштабируются вверх/вниз, но при этом сохраняют свой общий стиль.
Моя текущая реализация использует гибридный подход QProxyStyle + QApplication.setStyleSheet(...)
Эта текущая реализация работает очень хорошо для небольших/простых приложений с примерно Около 15 различных виджетов (таблицы, списки, деревья, поля ввода, метки, флажки, ползунки), но для более крупных/сложных приложений пользовательский интерфейс замораживается на долгое время, прежде чем вы увидите масштабированное содержимое.
Есть ли более быстрый и надежный способ сделать это?
Любые советы будут очень признательны.

Окружающая среда:
  • ОС: Windows 11
  • Python: 3.11
  • PySide6: 6.10.0
Вот мои классы
  • Унаследованный стиль прокси
from PySide6.QtWidgets import QStyle, QProxyStyle

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.QtWidgets as qtw
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)

Вернуться в «Python»