Coverage for graphica/gui/widgets/slider_spin.py: 97.5%
38 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
1"""スライダー+今のスピンボックス。値の持ち主はスピンボックスのまま(バインディングはそちらを見る)。"""
2from PySide6.QtCore import Qt
3from PySide6.QtWidgets import QAbstractSpinBox, QHBoxLayout, QSlider, QWidget
5SPIN_WIDTH = 56
8class SliderSpin(QWidget):
9 """spinbox を中に取り込み、左にスライダーを付ける。
11 スライダーの範囲(slider_min〜slider_max)はよく使う範囲で、スピンボックスはそれより外の値も受け付ける
12 (そのときスライダーは端に止まる)。スピンボックスがシグナルを止めて書き換えられた(バインディングの
13 「戻す」)後は、refresh() でスライダーを合わせる。
14 """
16 def __init__(self, spinbox, slider_min, slider_max, step=None, parent=None):
17 super().__init__(parent)
18 self.spinbox = spinbox
19 self._scale = 10 ** spinbox.decimals()
20 self.slider = QSlider(Qt.Orientation.Horizontal, self)
21 self.slider.setObjectName("slider_spin_slider")
22 self.slider.setRange(round(slider_min * self._scale), round(slider_max * self._scale))
23 self.slider.setSingleStep(max(1, round((step or spinbox.singleStep()) * self._scale)))
24 self.slider.setCursor(Qt.CursorShape.PointingHandCursor)
25 layout = QHBoxLayout(self)
26 layout.setContentsMargins(0, 0, 0, 0)
27 layout.setSpacing(10)
28 layout.addWidget(self.slider, 1)
29 layout.addWidget(spinbox)
30 # 見本どおり、上下の矢印を消した数値だけの小さな欄にする(矢印の分の余白は QSS の sliderValue で外す)
31 spinbox.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
32 spinbox.setAlignment(Qt.AlignmentFlag.AlignCenter)
33 spinbox.setProperty("sliderValue", True)
34 # 既に表示に使われた部品は、プロパティを変えても QSS を当て直さないと見た目が変わらない
35 spinbox.style().unpolish(spinbox)
36 spinbox.style().polish(spinbox)
37 spinbox.setFixedWidth(SPIN_WIDTH)
38 self.slider.valueChanged.connect(self._on_slider_moved)
39 spinbox.valueChanged.connect(lambda _value: self.refresh())
40 self.refresh()
42 def refresh(self):
43 blocked = self.slider.blockSignals(True)
44 self.slider.setValue(round(self.spinbox.value() * self._scale))
45 self.slider.blockSignals(blocked)
47 def _on_slider_moved(self, position):
48 value = position / self._scale
49 if abs(value - self.spinbox.value()) >= 0.5 / self._scale: 49 ↛ exitline 49 didn't return from function '_on_slider_moved' because the condition on line 49 was always true
50 self.spinbox.setValue(value)
52 def setEnabled(self, enabled):
53 super().setEnabled(enabled)
54 self.spinbox.setEnabled(enabled)