mirror of
https://github.com/pyapp-kit/superqt.git
synced 2026-01-04 19:31:24 +01:00
Labeled sliders (#3)
* good labels * more options * add to init * reemit value changed * remove pass * refine positioning * update example * add docs
This commit is contained in:
83
README.md
83
README.md
@@ -106,14 +106,14 @@ sliderMoved(Tuple[int, ...])
|
|||||||
|
|
||||||
These options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.
|
These options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.
|
||||||
|
|
||||||
| getter | setter | type | default | description |
|
| getter | setter | type | default | description |
|
||||||
| ------------- | ------------- |--------- | -------- | --------- |
|
| -------------------- | ------------------------------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------ |
|
||||||
| `barIsVisible` | `setBarIsVisible` <br>`hideBar` / `showBar` | `bool` | `True` | <small>Whether the bar between handles is visible.</small> |
|
| `barIsVisible` | `setBarIsVisible` <br>`hideBar` / `showBar` | `bool` | `True` | <small>Whether the bar between handles is visible.</small> |
|
||||||
| `barMovesAllHandles` | `setBarMovesAllHandles` | `bool` | `True` | <small>Whether clicking on the bar moves all handles or just the nearest</small> |
|
| `barMovesAllHandles` | `setBarMovesAllHandles` | `bool` | `True` | <small>Whether clicking on the bar moves all handles or just the nearest</small> |
|
||||||
| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or "elastic" when dragging the bar beyond min/max.</small> |
|
| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or "elastic" when dragging the bar beyond min/max.</small> |
|
||||||
------
|
------
|
||||||
|
|
||||||
## Example
|
## Examples
|
||||||
|
|
||||||
These screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`
|
These screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`
|
||||||
(single handle). With no styles applied, `QRangeSlider` will match the native OS
|
(single handle). With no styles applied, `QRangeSlider` will match the native OS
|
||||||
@@ -178,18 +178,81 @@ QRangeSlider {
|
|||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
##### Catalina
|
##### Catalina
|
||||||

|

|
||||||
|
|
||||||
##### Big Sur
|
##### Big Sur
|
||||||

|

|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
## Labeled Sliders
|
||||||
|
|
||||||
|
This package also includes two "labeled" slider variants. One for `QRangeSlider`, and one for the native `QSlider`:
|
||||||
|
|
||||||
|
### `QLabeledRangeSlider`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```python
|
||||||
|
from qtrangeslider import QLabeledRangeSlider
|
||||||
|
```
|
||||||
|
|
||||||
|
This has the same API as `QRangeSlider` with the following additional options:
|
||||||
|
|
||||||
|
#### `handleLabelPosition`/`setHandleLabelPosition`
|
||||||
|
|
||||||
|
Where/whether labels are shown adjacent to slider handles.
|
||||||
|
|
||||||
|
**type:** `QLabeledRangeSlider.LabelPosition`
|
||||||
|
|
||||||
|
**default:** `LabelPosition.LabelsAbove`
|
||||||
|
|
||||||
|
*options:*
|
||||||
|
|
||||||
|
- `LabelPosition.NoLabel` (no labels shown adjacent to handles)
|
||||||
|
- `LabelPosition.LabelsAbove`
|
||||||
|
- `LabelPosition.LabelsBelow`
|
||||||
|
- `LabelPosition.LabelsRight` (alias for `LabelPosition.LabelsAbove`)
|
||||||
|
- `LabelPosition.LabelsLeft` (alias for `LabelPosition.LabelsBelow`)
|
||||||
|
|
||||||
|
|
||||||
|
#### `edgeLabelMode`/`setEdgeLabelMode`
|
||||||
|
|
||||||
|
**type:** `QLabeledRangeSlider.EdgeLabelMode`
|
||||||
|
|
||||||
|
**default:** `EdgeLabelMode.LabelsAbove`
|
||||||
|
|
||||||
|
*options:*
|
||||||
|
|
||||||
|
- `EdgeLabelMode.NoLabel`: no labels shown at slider extremes
|
||||||
|
- `EdgeLabelMode.LabelIsRange`: edge labels shown the min/max values
|
||||||
|
- `EdgeLabelMode.LabelIsValue`: edge labels shown the slider range
|
||||||
|
|
||||||
|
|
||||||
|
#### fine tuning position of labels:
|
||||||
|
|
||||||
|
If you find that you need to fine tune the position of the handle labels:
|
||||||
|
|
||||||
|
- `QLabeledRangeSlider.label_shift_x`: adjust horizontal label position
|
||||||
|
- `QLabeledRangeSlider.label_shift_y`: adjust vertical label position
|
||||||
|
|
||||||
|
### `QLabeledSlider`
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```python
|
||||||
|
from qtrangeslider import QLabeledSlider
|
||||||
|
```
|
||||||
|
|
||||||
|
(no additional options at this point)
|
||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
|
|||||||
17
examples/labeled.py
Normal file
17
examples/labeled.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from qtrangeslider._labeled import QLabeledRangeSlider, QLabeledSlider
|
||||||
|
from qtrangeslider.qtcompat.QtCore import Qt
|
||||||
|
from qtrangeslider.qtcompat.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||||
|
|
||||||
|
app = QApplication([])
|
||||||
|
|
||||||
|
w = QWidget()
|
||||||
|
sld = QLabeledRangeSlider()
|
||||||
|
|
||||||
|
sld.setRange(0, 500)
|
||||||
|
sld.setValue((100, 400))
|
||||||
|
w.setLayout(QVBoxLayout())
|
||||||
|
w.layout().addWidget(sld)
|
||||||
|
w.layout().addWidget(QLabeledSlider(Qt.Horizontal))
|
||||||
|
w.show()
|
||||||
|
w.resize(500, 150)
|
||||||
|
app.exec_()
|
||||||
BIN
images/labeled_qslider.png
Normal file
BIN
images/labeled_qslider.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
BIN
images/labeled_range.png
Normal file
BIN
images/labeled_range.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -3,6 +3,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
__version__ = "unknown"
|
__version__ = "unknown"
|
||||||
|
|
||||||
|
from ._labeled import QLabeledRangeSlider, QLabeledSlider
|
||||||
from ._qrangeslider import QRangeSlider
|
from ._qrangeslider import QRangeSlider
|
||||||
|
|
||||||
__all__ = ["QRangeSlider"]
|
__all__ = ["QRangeSlider", "QLabeledRangeSlider", "QLabeledSlider"]
|
||||||
|
|||||||
362
qtrangeslider/_labeled.py
Normal file
362
qtrangeslider/_labeled.py
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from ._qrangeslider import QRangeSlider
|
||||||
|
from .qtcompat.QtCore import QPoint, QSize, Qt, Signal
|
||||||
|
from .qtcompat.QtGui import QFontMetrics
|
||||||
|
from .qtcompat.QtWidgets import (
|
||||||
|
QAbstractSlider,
|
||||||
|
QApplication,
|
||||||
|
QHBoxLayout,
|
||||||
|
QSlider,
|
||||||
|
QSpinBox,
|
||||||
|
QStyle,
|
||||||
|
QStyleOptionSpinBox,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LabelPosition(IntEnum):
|
||||||
|
NoLabel = 0
|
||||||
|
LabelsAbove = 1
|
||||||
|
LabelsBelow = 2
|
||||||
|
LabelsRight = 1
|
||||||
|
LabelsLeft = 2
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeLabelMode(IntEnum):
|
||||||
|
NoLabel = 0
|
||||||
|
LabelIsRange = 1
|
||||||
|
LabelIsValue = 2
|
||||||
|
|
||||||
|
|
||||||
|
class QLabeledSlider(QAbstractSlider):
|
||||||
|
def __init__(self, *args) -> None:
|
||||||
|
parent = None
|
||||||
|
orientation = Qt.Horizontal
|
||||||
|
if len(args) == 2:
|
||||||
|
orientation, parent = args
|
||||||
|
elif args:
|
||||||
|
if isinstance(args[0], QWidget):
|
||||||
|
parent = args[0]
|
||||||
|
else:
|
||||||
|
orientation = args[0]
|
||||||
|
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._slider = QSlider()
|
||||||
|
self._slider.valueChanged.connect(self.valueChanged.emit)
|
||||||
|
self._label = SliderLabel(self._slider, connect=self.setValue)
|
||||||
|
|
||||||
|
self.valueChanged.connect(self._label.setValue)
|
||||||
|
self.valueChanged.connect(self._slider.setValue)
|
||||||
|
self.rangeChanged.connect(self._slider.setRange)
|
||||||
|
|
||||||
|
self._slider.valueChanged.connect(self.setValue)
|
||||||
|
self.setOrientation(orientation)
|
||||||
|
|
||||||
|
def setOrientation(self, orientation):
|
||||||
|
"""Set orientation, value will be 'horizontal' or 'vertical'."""
|
||||||
|
self._slider.setOrientation(orientation)
|
||||||
|
if orientation == Qt.Vertical:
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(self._slider, alignment=Qt.AlignHCenter)
|
||||||
|
layout.addWidget(self._label, alignment=Qt.AlignHCenter)
|
||||||
|
self._label.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.setSpacing(1)
|
||||||
|
else:
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.addWidget(self._slider)
|
||||||
|
layout.addWidget(self._label)
|
||||||
|
self._label.setAlignment(Qt.AlignRight)
|
||||||
|
layout.setSpacing(10)
|
||||||
|
|
||||||
|
old_layout = self.layout()
|
||||||
|
if old_layout is not None:
|
||||||
|
QWidget().setLayout(old_layout)
|
||||||
|
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
class QLabeledRangeSlider(QAbstractSlider):
|
||||||
|
valueChanged = Signal(tuple)
|
||||||
|
LabelPosition = LabelPosition
|
||||||
|
EdgeLabelMode = EdgeLabelMode
|
||||||
|
|
||||||
|
def __init__(self, *args) -> None:
|
||||||
|
parent = None
|
||||||
|
orientation = Qt.Horizontal
|
||||||
|
if len(args) == 2:
|
||||||
|
orientation, parent = args
|
||||||
|
elif args:
|
||||||
|
if isinstance(args[0], QWidget):
|
||||||
|
parent = args[0]
|
||||||
|
else:
|
||||||
|
orientation = args[0]
|
||||||
|
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setAttribute(Qt.WA_ShowWithoutActivating)
|
||||||
|
self._handle_labels = []
|
||||||
|
self._handle_label_position: LabelPosition = LabelPosition.LabelsAbove
|
||||||
|
|
||||||
|
# for fine tuning label position
|
||||||
|
self.label_shift_x = 0
|
||||||
|
self.label_shift_y = 0
|
||||||
|
|
||||||
|
self._slider = QRangeSlider()
|
||||||
|
self._slider.valueChanged.connect(self.valueChanged.emit)
|
||||||
|
|
||||||
|
self._min_label = SliderLabel(
|
||||||
|
self._slider, alignment=Qt.AlignLeft, connect=self._min_label_edited
|
||||||
|
)
|
||||||
|
self._max_label = SliderLabel(
|
||||||
|
self._slider, alignment=Qt.AlignRight, connect=self._max_label_edited
|
||||||
|
)
|
||||||
|
self.setEdgeLabelMode(EdgeLabelMode.LabelIsRange)
|
||||||
|
|
||||||
|
self._slider.valueChanged.connect(self._on_value_changed)
|
||||||
|
self.rangeChanged.connect(self._on_range_changed)
|
||||||
|
|
||||||
|
self._on_value_changed(self._slider.value())
|
||||||
|
self._on_range_changed(self._slider.minimum(), self._slider.maximum())
|
||||||
|
self.setOrientation(orientation)
|
||||||
|
|
||||||
|
def handleLabelPosition(self) -> LabelPosition:
|
||||||
|
return self._handle_label_position
|
||||||
|
|
||||||
|
def setHandleLabelPosition(self, opt: LabelPosition) -> LabelPosition:
|
||||||
|
self._handle_label_position = opt
|
||||||
|
for lbl in self._handle_labels:
|
||||||
|
if not opt:
|
||||||
|
lbl.hide()
|
||||||
|
else:
|
||||||
|
lbl.show()
|
||||||
|
self.setOrientation(self.orientation())
|
||||||
|
|
||||||
|
def edgeLabelMode(self) -> EdgeLabelMode:
|
||||||
|
return self._edge_label_mode
|
||||||
|
|
||||||
|
def setEdgeLabelMode(self, opt: EdgeLabelMode):
|
||||||
|
self._edge_label_mode = opt
|
||||||
|
if not self._edge_label_mode:
|
||||||
|
self._min_label.hide()
|
||||||
|
self._max_label.hide()
|
||||||
|
else:
|
||||||
|
if self.isVisible():
|
||||||
|
self._min_label.show()
|
||||||
|
self._max_label.show()
|
||||||
|
self._min_label.setMode(opt)
|
||||||
|
self._max_label.setMode(opt)
|
||||||
|
if opt == EdgeLabelMode.LabelIsValue:
|
||||||
|
v0, *_, v1 = self._slider.value()
|
||||||
|
self._min_label.setValue(v0)
|
||||||
|
self._max_label.setValue(v1)
|
||||||
|
elif opt == EdgeLabelMode.LabelIsRange:
|
||||||
|
self._min_label.setValue(self._slider.minimum())
|
||||||
|
self._max_label.setValue(self._slider.maximum())
|
||||||
|
QApplication.processEvents()
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def _reposition_labels(self):
|
||||||
|
if not self._handle_labels:
|
||||||
|
return
|
||||||
|
|
||||||
|
horizontal = self.orientation() == Qt.Horizontal
|
||||||
|
labels_above = self._handle_label_position == LabelPosition.LabelsAbove
|
||||||
|
|
||||||
|
for label, rect in zip(self._handle_labels, self._slider._handleRects()):
|
||||||
|
dx = -label.width() / 2
|
||||||
|
dy = -label.height() / 2
|
||||||
|
if labels_above:
|
||||||
|
if horizontal:
|
||||||
|
dy *= 3
|
||||||
|
else:
|
||||||
|
dx *= -1
|
||||||
|
else:
|
||||||
|
if horizontal:
|
||||||
|
dy *= -1
|
||||||
|
else:
|
||||||
|
dx *= 3
|
||||||
|
pos = self._slider.mapToParent(rect.center())
|
||||||
|
pos += QPoint(dx + self.label_shift_x, dy + self.label_shift_y)
|
||||||
|
label.move(pos)
|
||||||
|
label.clearFocus()
|
||||||
|
|
||||||
|
def _min_label_edited(self, val):
|
||||||
|
if self._edge_label_mode == EdgeLabelMode.LabelIsRange:
|
||||||
|
self.setMinimum(val)
|
||||||
|
else:
|
||||||
|
v = list(self._slider.value())
|
||||||
|
v[0] = val
|
||||||
|
self.setValue(v)
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def _max_label_edited(self, val):
|
||||||
|
if self._edge_label_mode == EdgeLabelMode.LabelIsRange:
|
||||||
|
self.setMaximum(val)
|
||||||
|
else:
|
||||||
|
v = list(self._slider.value())
|
||||||
|
v[-1] = val
|
||||||
|
self.setValue(v)
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def _on_value_changed(self, v):
|
||||||
|
if self._edge_label_mode == EdgeLabelMode.LabelIsValue:
|
||||||
|
self._min_label.setValue(v[0])
|
||||||
|
self._max_label.setValue(v[-1])
|
||||||
|
|
||||||
|
if len(v) != len(self._handle_labels):
|
||||||
|
for lbl in self._handle_labels:
|
||||||
|
lbl.setParent(None)
|
||||||
|
lbl.deleteLater()
|
||||||
|
self._handle_labels.clear()
|
||||||
|
for n, val in enumerate(self._slider.value()):
|
||||||
|
_cb = partial(self._slider._setSliderPositionAt, n)
|
||||||
|
s = SliderLabel(self._slider, parent=self, connect=_cb)
|
||||||
|
s.setValue(val)
|
||||||
|
self._handle_labels.append(s)
|
||||||
|
else:
|
||||||
|
for val, label in zip(v, self._handle_labels):
|
||||||
|
label.setValue(val)
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def _on_range_changed(self, min, max):
|
||||||
|
self._slider.setRange(min, max)
|
||||||
|
for lbl in self._handle_labels:
|
||||||
|
lbl.setRange(min, max)
|
||||||
|
if self._edge_label_mode == EdgeLabelMode.LabelIsRange:
|
||||||
|
self._min_label.setValue(min)
|
||||||
|
self._max_label.setValue(max)
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def value(self):
|
||||||
|
return self._slider.value()
|
||||||
|
|
||||||
|
def setValue(self, v: int) -> None:
|
||||||
|
self._slider.setValue(v)
|
||||||
|
self.sliderChange(QSlider.SliderValueChange)
|
||||||
|
|
||||||
|
def setOrientation(self, orientation):
|
||||||
|
"""Set orientation, value will be 'horizontal' or 'vertical'."""
|
||||||
|
|
||||||
|
self._slider.setOrientation(orientation)
|
||||||
|
if orientation == Qt.Vertical:
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.setSpacing(1)
|
||||||
|
layout.addWidget(self._max_label)
|
||||||
|
layout.addWidget(self._slider)
|
||||||
|
layout.addWidget(self._min_label)
|
||||||
|
# TODO: set margins based on label width
|
||||||
|
if self._handle_label_position == LabelPosition.LabelsLeft:
|
||||||
|
marg = (30, 0, 0, 0)
|
||||||
|
elif self._handle_label_position == LabelPosition.NoLabel:
|
||||||
|
marg = (0, 0, 0, 0)
|
||||||
|
else:
|
||||||
|
marg = (0, 0, 20, 0)
|
||||||
|
layout.setAlignment(Qt.AlignCenter)
|
||||||
|
else:
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.setSpacing(7)
|
||||||
|
if self._handle_label_position == LabelPosition.LabelsBelow:
|
||||||
|
marg = (0, 0, 0, 25)
|
||||||
|
elif self._handle_label_position == LabelPosition.NoLabel:
|
||||||
|
marg = (0, 0, 0, 0)
|
||||||
|
else:
|
||||||
|
marg = (0, 25, 0, 0)
|
||||||
|
layout.addWidget(self._min_label)
|
||||||
|
layout.addWidget(self._slider)
|
||||||
|
layout.addWidget(self._max_label)
|
||||||
|
|
||||||
|
# remove old layout
|
||||||
|
old_layout = self.layout()
|
||||||
|
if old_layout is not None:
|
||||||
|
QWidget().setLayout(old_layout)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
layout.setContentsMargins(*marg)
|
||||||
|
super().setOrientation(orientation)
|
||||||
|
QApplication.processEvents()
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
def resizeEvent(self, a0) -> None:
|
||||||
|
super().resizeEvent(a0)
|
||||||
|
self._reposition_labels()
|
||||||
|
|
||||||
|
|
||||||
|
class SliderLabel(QSpinBox):
|
||||||
|
def __init__(
|
||||||
|
self, slider: QSlider, parent=None, alignment=Qt.AlignCenter, connect=None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
self._slider = slider
|
||||||
|
self.setFocusPolicy(Qt.ClickFocus)
|
||||||
|
self.setMode(EdgeLabelMode.LabelIsValue)
|
||||||
|
|
||||||
|
self.setRange(slider.minimum(), slider.maximum())
|
||||||
|
slider.rangeChanged.connect(self._update_size)
|
||||||
|
self.setAlignment(alignment)
|
||||||
|
self.setButtonSymbols(QSpinBox.NoButtons)
|
||||||
|
self.setStyleSheet("background:transparent; border: 0;")
|
||||||
|
if connect is not None:
|
||||||
|
self.editingFinished.connect(lambda: connect(self.value()))
|
||||||
|
self.editingFinished.connect(self.clearFocus)
|
||||||
|
self._update_size()
|
||||||
|
|
||||||
|
def _update_size(self):
|
||||||
|
# fontmetrics to measure the width of text
|
||||||
|
fm = QFontMetrics(self.font())
|
||||||
|
h = self.sizeHint().height()
|
||||||
|
fixed_content = self.prefix() + self.suffix() + " "
|
||||||
|
|
||||||
|
if self._mode == EdgeLabelMode.LabelIsValue:
|
||||||
|
# determine width based on min/max/specialValue
|
||||||
|
s = self.textFromValue(self.minimum())[:18] + fixed_content
|
||||||
|
w = max(0, fm.horizontalAdvance(s))
|
||||||
|
s = self.textFromValue(self.maximum())[:18] + fixed_content
|
||||||
|
w = max(w, fm.horizontalAdvance(s))
|
||||||
|
if self.specialValueText():
|
||||||
|
w = max(w, fm.horizontalAdvance(self.specialValueText()))
|
||||||
|
else:
|
||||||
|
s = self.textFromValue(self.value())
|
||||||
|
w = max(0, fm.horizontalAdvance(s)) + 3
|
||||||
|
|
||||||
|
w += 3 # cursor blinking space
|
||||||
|
# get the final size hint
|
||||||
|
opt = QStyleOptionSpinBox()
|
||||||
|
self.initStyleOption(opt)
|
||||||
|
size = self.style().sizeFromContents(QStyle.CT_SpinBox, opt, QSize(w, h), self)
|
||||||
|
self.setFixedSize(size)
|
||||||
|
|
||||||
|
def setValue(self, val):
|
||||||
|
super().setValue(val)
|
||||||
|
if self._mode == EdgeLabelMode.LabelIsRange:
|
||||||
|
self._update_size()
|
||||||
|
|
||||||
|
def setMaximum(self, max: int) -> None:
|
||||||
|
super().setMaximum(max)
|
||||||
|
if self._mode == EdgeLabelMode.LabelIsValue:
|
||||||
|
self._update_size()
|
||||||
|
|
||||||
|
def setMinimum(self, min: int) -> None:
|
||||||
|
super().setMinimum(min)
|
||||||
|
if self._mode == EdgeLabelMode.LabelIsValue:
|
||||||
|
self._update_size()
|
||||||
|
|
||||||
|
def setMode(self, opt: EdgeLabelMode):
|
||||||
|
# when the edge labels are controlling slider range,
|
||||||
|
# we want them to have a big range, but not have a huge label
|
||||||
|
self._mode = opt
|
||||||
|
if opt == EdgeLabelMode.LabelIsRange:
|
||||||
|
self.setMinimum(-9999999)
|
||||||
|
self.setMaximum(9999999)
|
||||||
|
try:
|
||||||
|
self._slider.rangeChanged.disconnect(self.setRange)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.setMinimum(self._slider.minimum())
|
||||||
|
self.setMaximum(self._slider.maximum())
|
||||||
|
self._slider.rangeChanged.connect(self.setRange)
|
||||||
|
self._update_size()
|
||||||
@@ -196,7 +196,7 @@ class QRangeSlider(QSlider):
|
|||||||
offset = self.minimum() - ref[0]
|
offset = self.minimum() - ref[0]
|
||||||
self.setSliderPosition([i + offset for i in ref])
|
self.setSliderPosition([i + offset for i in ref])
|
||||||
|
|
||||||
def _spreadAllPositions(self, shrink=False, gain=1.2, ref=None) -> None:
|
def _spreadAllPositions(self, shrink=False, gain=1.1, ref=None) -> None:
|
||||||
if ref is None:
|
if ref is None:
|
||||||
ref = self._position
|
ref = self._position
|
||||||
# if self._bar_is_rigid: # TODO
|
# if self._bar_is_rigid: # TODO
|
||||||
@@ -351,8 +351,13 @@ class QRangeSlider(QSlider):
|
|||||||
super().setRange(min, max)
|
super().setRange(min, max)
|
||||||
self.setValue(self._value) # re-bound
|
self.setValue(self._value) # re-bound
|
||||||
|
|
||||||
def _handleRects(self, opt: QStyleOptionSlider, handle_index: int = None) -> QRect:
|
def _handleRects(
|
||||||
|
self, opt: QStyleOptionSlider = None, handle_index: int = None
|
||||||
|
) -> QRect:
|
||||||
"""Return the QRect for all handles."""
|
"""Return the QRect for all handles."""
|
||||||
|
if opt is None:
|
||||||
|
opt = self._getStyleOption()
|
||||||
|
|
||||||
style = self.style().proxy()
|
style = self.style().proxy()
|
||||||
|
|
||||||
if handle_index is not None: # get specific handle rect
|
if handle_index is not None: # get specific handle rect
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ elif PYQT6:
|
|||||||
|
|
||||||
# backwards compat with PyQt5
|
# backwards compat with PyQt5
|
||||||
# namespace moves:
|
# namespace moves:
|
||||||
for cls in (QStyle, QSlider, QSizePolicy):
|
for cls in (QStyle, QSlider, QSizePolicy, QSpinBox):
|
||||||
for attr in dir(cls):
|
for attr in dir(cls):
|
||||||
if not attr[0].isupper():
|
if not attr[0].isupper():
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user