more readme

This commit is contained in:
Talley Lambert
2021-04-24 23:35:43 -04:00
parent 9fde133977
commit 487921c791
7 changed files with 94 additions and 25 deletions

View File

@@ -106,11 +106,11 @@ jobs:
if: runner.os == 'Linux' && matrix.screenshot
uses: GabrielBB/xvfb-action@v1
with:
run: python examples/screenshots.py
run: python examples/demo_widget.py
- name: Screenshots
if: runner.os != 'Linux' && matrix.screenshot
run: python examples/screenshots.py
run: python examples/demo_widget.py
- uses: actions/upload-artifact@v2
if: matrix.screenshot

1
.gitignore vendored
View File

@@ -77,3 +77,4 @@ target/
# written by setuptools_scm
*/_version.py
.vscode/settings.json

View File

@@ -7,7 +7,7 @@ Version](https://img.shields.io/pypi/pyversions/QtRangeSlider.svg?color=green)](
[![Test](https://github.com/tlambert03/QtRangeSlider/actions/workflows/test_and_deploy.yml/badge.svg)](https://github.com/tlambert03/QtRangeSlider/actions/workflows/test_and_deploy.yml)
[![codecov](https://codecov.io/gh/tlambert03/QtRangeSlider/branch/master/graph/badge.svg)](https://codecov.io/gh/tlambert03/QtRangeSlider)
**Multi-handle range slider widget for PyQt/PySide**
**The missing multi-handle range slider widget for PyQt & PySide**
![slider](screenshots/slider.png)
@@ -31,24 +31,78 @@ You can install `QtRangeSlider` via pip:
```sh
pip install qtrangeslider
# note: you must also install a Qt Backend
# supports PyQt5, PySide2, PyQt6, and PySide6
# as a convenience you can install via extras:
# NOTE: you must also install a Qt Backend.
# PyQt5, PySide2, PyQt6, and PySide6 are supported
# As a convenience you can install them as extras:
pip install qtrangeslider[pyqt5]
```
And then to use it:
```python
from qtrangeslider import QRangeSlider
```
------
## API
As `QRangeSlider` inherits from `QtWidgets.QSlider`, you can use all of the
same methods available in the [QSlider API](https://doc.qt.io/qt-5/qslider.html)
To create a slider:
```python
from qtrangeslider import QRangeSlider
# as usual:
# you must create a QApplication before create a widget.
range_slider = QRangeSlider()
```
As `QRangeSlider` inherits from `QtWidgets.QSlider`, you can use all of the
same methods available in the [QSlider API](https://doc.qt.io/qt-5/qslider.html). The major difference is that `value` and `sliderPosition` are reimplemented as `tuples` of `int` (where the length of the tuple is equal to the number of handles in the slider.)
### value: Tuple[int, ...]
This property holds the current value of all handles in the slider.
The slider forces all values to be within the legal range:
`minimum <= value <= maximum`.
Changing the value also changes the sliderPosition.
##### Access Functions:
```python
range_slider.value() -> Tuple[int, ...]
```
```python
range_slider.setValue(val: Sequence[int]) -> None
```
##### Notifier Signal:
```python
valueChanged(Tuple[int, ...])
```
### sliderPosition: Tuple[int, ...]
This property holds the current slider positions. It is a `tuple` with length equal to the number of handles.
If [tracking](https://doc.qt.io/qt-5/qabstractslider.html#tracking-prop) is enabled (the default), this is identical to [`value`](#value--tupleint-).
##### Access Functions:
```python
range_slider.sliderPosition() -> Tuple[int, ...]
```
```python
range_slider.setSliderPosition(val: Sequence[int]) -> None
```
##### Notifier Signal:
```python
sliderMoved(Tuple[int, ...])
```
------
## Example
@@ -59,6 +113,8 @@ using [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet-reference.html), then
`QRangeSlider` will inherit any styles applied to `QSlider` (since it inherits
from QSlider).
> The code for these example widgets is [here](examples/demo_widget.py)
<details>
<summary><em>See style sheet used for this example</em></summary>
@@ -112,5 +168,4 @@ QSlider::sub-page:horizontal {
If you encounter any problems, please [file an issue] along with a detailed
description.
[file an issue]: https://github.com/tlambert03/QtRangeSlider/issues

View File

@@ -4,8 +4,7 @@ from qtrangeslider.qtcompat.QtWidgets import QApplication
app = QApplication([])
slider = QRangeSlider()
slider.setMinimum(0)
slider.setMaximum(100)
slider.setValue((20, 80))
slider.show()

View File

@@ -15,11 +15,6 @@ from .qtcompat.QtWidgets import (
Control = Tuple[str, int]
def _bound(min_: int, max_: int, value: int) -> int:
"""Return value bounded by min_ and max_."""
return max(min_, min(max_, value))
class QRangeSlider(QSlider):
# Emitted when the slider value has changed, with the new slider values
valueChanged = Signal(tuple)
@@ -85,6 +80,9 @@ class QRangeSlider(QSlider):
return tuple(self._position)
def setSliderPosition(self, sld_idx: int, pos: int) -> None:
# TODO: make it take a tuple, and assert that the length is correct
# only setting `value` is allowed to change the number of handles
pos = self._min_max_bound(pos)
# prevent sliders from moving beyond their neighbors
pos = self._neighbor_bound(pos, sld_idx, self._position)
@@ -192,8 +190,11 @@ class QRangeSlider(QSlider):
self.update()
self.setSliderDown(True)
elif self._pressedControl[0] == "bar":
self.setRepeatAction(QSlider.SliderNoAction) # why again?
self._clickOffset = self._pixelPosToRangeValue(self._pick(ev.pos()))
self._sldPosAtPress = tuple(self._position)
self.update()
self.setSliderDown(True)
def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None:
# TODO: add pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
@@ -230,7 +231,7 @@ class QRangeSlider(QSlider):
old_pressed = self._pressedControl
self._pressedControl = self.NULL_CTRL
self.setRepeatAction(QSlider.SliderNoAction)
if old_pressed[0] == "handle":
if old_pressed[0] in ("handle", "bar"):
self.setSliderDown(False)
self.update() # TODO: restrict to the rect of old_pressed
@@ -489,6 +490,13 @@ class QRangeSlider(QSlider):
setattr(self, f"_bar_{dim}", float(bgrd.groups()[-1]))
def _bound(min_: int, max_: int, value: int) -> int:
"""Return value bounded by min_ and max_."""
return max(min_, min(max_, value))
# Styles Parsing ##############
qlineargrad_pattern = re.compile(
r"""
qlineargradient\(

View File

@@ -31,13 +31,13 @@ QT_API = "QT_API"
# Names of the expected PyQt5 api
PYQT5_API = ["pyqt5"]
# Names of the expected PyQt5 api
# Names of the expected PyQt6 api
PYQT6_API = ["pyqt6"]
# Names of the expected PySide2 api
PYSIDE2_API = ["pyside2"]
# Names of the expected PySide2 api
# Names of the expected PySide6 api
PYSIDE6_API = ["pyside6"]
# Detecting if a binding was specified by the user
@@ -142,7 +142,13 @@ if API in PYSIDE6_API:
PYSIDE6 = True
except ImportError:
raise PythonQtError("No Qt bindings could be found")
API = None
if API is None:
raise PythonQtError(
"No Qt bindings could be found.\nYou must install one of the following packages "
"to use QtRangeSlider: PyQt5, PyQt6, PySide2, or PySide6"
)
# If a correct API name is passed to QT_API and it could not be found,
# switches to another and informs through the warning