# QtRangeSlider
[![License](https://img.shields.io/pypi/l/QtRangeSlider.svg?color=green)](https://github.com/tlambert03/QtRangeSlider/raw/master/LICENSE)
[![PyPI](https://img.shields.io/pypi/v/QtRangeSlider.svg?color=green)](https://pypi.org/project/QtRangeSlider)
[![Python
Version](https://img.shields.io/pypi/pyversions/QtRangeSlider.svg?color=green)](https://python.org)
[![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)
**The missing multi-handle range slider widget for PyQt & PySide**
![slider](images/slider.png)
The goal of this package is to provide a Range Slider (a slider with 2 or more
handles) that feels as "native" as possible. Styles should match the OS by
default, and the slider should behave like a standard
[`QSlider`](https://doc.qt.io/qt-5/qslider.html)... but with multiple handles!
- `QRangeSlider` inherits from [`QSlider`](https://doc.qt.io/qt-5/qslider.html)
and attempts to match the Qt API as closely as possible
- Uses platform-specific styles (for handle, groove, & ticks) but also supports
QSS style sheets.
- Supports mouse wheel and keypress (soon) events
- Supports PyQt5, PyQt6, PySide2 and PySide6
- Supports more than 2 handles (e.g. `slider.setValue([0, 10, 60, 80])`)
## Installation
You can install `QtRangeSlider` via pip:
```sh
pip install qtrangeslider
# 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]
```
------
## API
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, ...])
```
### Additional properties
These options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.
| getter | setter | type | default | description |
| -------------------- | ------------------------------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------ |
| `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> |
| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or "elastic" when dragging the bar beyond min/max.</small> |
------
## Examples
These screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`
(single handle). With no styles applied, `QRangeSlider` will match the native OS
style of `QSlider` – with or without tick marks. When styles have been applied
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). If you'd like to style `QRangeSlider` differently than `QSlider`,
then you can also target it directly in your style sheet. The one "special"
property for QRangeSlider is `qproperty-barColor`, which sets the color of the
bar between the handles.
> The code for these example widgets is [here](examples/demo_widget.py)
<details>
<summary><em>See style sheet used for this example</em></summary>
```css
/*
Because QRangeSlider inherits from QSlider, it will also inherit styles
*/
QSlider {
min-height: 20px;
}
QSlider::groove:horizontal {
border: 0px;
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
stop:0 #777, stop:1 #aaa);
height: 20px;
border-radius: 10px;
}
QSlider::handle {
background: qradialgradient(cx:0, cy:0, radius: 1.2, fx:0.5,
fy:0.5, stop:0 #eef, stop:1 #000);
height: 20px;
width: 20px;
border-radius: 10px;
}
/*
"QSlider::sub-page" is the one exception ...
(it styles the area to the left of the QSlider handle)
*/
QSlider::sub-page:horizontal {
background: #447;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
/*
for QRangeSlider: use "qproperty-barColor". "sub-page" will not work.
*/
QRangeSlider {
qproperty-barColor: #447;
}
```
</details>
### macOS
##### Catalina
![mac10](images/demo_darwin10.png)
##### Big Sur
![mac11](images/demo_darwin11.png)
### Windows
![window](images/demo_windows.png)
### Linux
![linux](images/demo_linux.png)
## Labeled Sliders
This package also includes two "labeled" slider variants. One for `QRangeSlider`, and one for the native `QSlider`:
### `QLabeledRangeSlider`
![labeled_range](images/labeled_range.png)
```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.LabelIsRange`
*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`
![labeled_range](images/labeled_qslider.png)
```python
from qtrangeslider import QLabeledSlider
```
(no additional options at this point)
## Issues
If you encounter any problems, please [file an issue] along with a detailed
description.
[file an issue]: https://github.com/tlambert03/QtRangeSlider/issues
Raw data
{
"_id": null,
"home_page": "https://github.com/tlambert03/QtRangeSlider",
"name": "QtRangeSlider",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "qt,range slider,widget",
"author": "Talley Lambert",
"author_email": "talley.lambert@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f4/3a/2c0ff8c9ca3773e198f4e5921ba81a095ff0910fd8079c19a8bbc0a96080/QtRangeSlider-0.1.5.tar.gz",
"platform": "",
"description": "# QtRangeSlider\n\n[![License](https://img.shields.io/pypi/l/QtRangeSlider.svg?color=green)](https://github.com/tlambert03/QtRangeSlider/raw/master/LICENSE)\n[![PyPI](https://img.shields.io/pypi/v/QtRangeSlider.svg?color=green)](https://pypi.org/project/QtRangeSlider)\n[![Python\nVersion](https://img.shields.io/pypi/pyversions/QtRangeSlider.svg?color=green)](https://python.org)\n[![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)\n[![codecov](https://codecov.io/gh/tlambert03/QtRangeSlider/branch/master/graph/badge.svg)](https://codecov.io/gh/tlambert03/QtRangeSlider)\n\n**The missing multi-handle range slider widget for PyQt & PySide**\n\n![slider](images/slider.png)\n\nThe goal of this package is to provide a Range Slider (a slider with 2 or more\nhandles) that feels as \"native\" as possible. Styles should match the OS by\ndefault, and the slider should behave like a standard\n[`QSlider`](https://doc.qt.io/qt-5/qslider.html)... but with multiple handles!\n\n- `QRangeSlider` inherits from [`QSlider`](https://doc.qt.io/qt-5/qslider.html)\n and attempts to match the Qt API as closely as possible\n- Uses platform-specific styles (for handle, groove, & ticks) but also supports\n QSS style sheets.\n- Supports mouse wheel and keypress (soon) events\n- Supports PyQt5, PyQt6, PySide2 and PySide6\n- Supports more than 2 handles (e.g. `slider.setValue([0, 10, 60, 80])`)\n\n## Installation\n\nYou can install `QtRangeSlider` via pip:\n\n```sh\npip install qtrangeslider\n\n# NOTE: you must also install a Qt Backend.\n# PyQt5, PySide2, PyQt6, and PySide6 are supported\n# As a convenience you can install them as extras:\npip install qtrangeslider[pyqt5]\n```\n\n\n------\n\n## API\n\nTo create a slider:\n\n```python\nfrom qtrangeslider import QRangeSlider\n\n# as usual:\n# you must create a QApplication before create a widget.\nrange_slider = QRangeSlider()\n```\n\nAs `QRangeSlider` inherits from `QtWidgets.QSlider`, you can use all of the\nsame 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.)\n\n### `value: Tuple[int, ...]`\n\nThis property holds the current value of all handles in the slider.\n\nThe slider forces all values to be within the legal range:\n`minimum <= value <= maximum`.\n\nChanging the value also changes the sliderPosition.\n\n##### Access Functions:\n\n```python\nrange_slider.value() -> Tuple[int, ...]\n```\n\n```python\nrange_slider.setValue(val: Sequence[int]) -> None\n```\n\n##### Notifier Signal:\n\n```python\nvalueChanged(Tuple[int, ...])\n```\n\n### `sliderPosition: Tuple[int, ...]`\n\nThis property holds the current slider positions. It is a `tuple` with length equal to the number of handles.\n\nIf [tracking](https://doc.qt.io/qt-5/qabstractslider.html#tracking-prop) is enabled (the default), this is identical to [`value`](#value--tupleint-).\n\n##### Access Functions:\n\n```python\nrange_slider.sliderPosition() -> Tuple[int, ...]\n```\n\n```python\nrange_slider.setSliderPosition(val: Sequence[int]) -> None\n```\n\n##### Notifier Signal:\n\n```python\nsliderMoved(Tuple[int, ...])\n```\n\n### Additional properties\n\nThese options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.\n\n| getter | setter | type | default | description |\n| -------------------- | ------------------------------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------ |\n| `barIsVisible` | `setBarIsVisible` <br>`hideBar` / `showBar` | `bool` | `True` | <small>Whether the bar between handles is visible.</small> |\n| `barMovesAllHandles` | `setBarMovesAllHandles` | `bool` | `True` | <small>Whether clicking on the bar moves all handles or just the nearest</small> |\n| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or \"elastic\" when dragging the bar beyond min/max.</small> |\n------\n\n## Examples\n\nThese screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`\n(single handle). With no styles applied, `QRangeSlider` will match the native OS\nstyle of `QSlider` \u2013 with or without tick marks. When styles have been applied\nusing [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet-reference.html), then\n`QRangeSlider` will inherit any styles applied to `QSlider` (since it inherits\nfrom QSlider). If you'd like to style `QRangeSlider` differently than `QSlider`,\nthen you can also target it directly in your style sheet. The one \"special\"\nproperty for QRangeSlider is `qproperty-barColor`, which sets the color of the\nbar between the handles.\n\n> The code for these example widgets is [here](examples/demo_widget.py)\n\n<details>\n\n<summary><em>See style sheet used for this example</em></summary>\n\n```css\n/*\nBecause QRangeSlider inherits from QSlider, it will also inherit styles\n*/\nQSlider {\n min-height: 20px;\n}\n\nQSlider::groove:horizontal {\n border: 0px;\n background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n stop:0 #777, stop:1 #aaa);\n height: 20px;\n border-radius: 10px;\n}\n\nQSlider::handle {\n background: qradialgradient(cx:0, cy:0, radius: 1.2, fx:0.5,\n fy:0.5, stop:0 #eef, stop:1 #000);\n height: 20px;\n width: 20px;\n border-radius: 10px;\n}\n\n/*\n\"QSlider::sub-page\" is the one exception ...\n(it styles the area to the left of the QSlider handle)\n*/\nQSlider::sub-page:horizontal {\n background: #447;\n border-top-left-radius: 10px;\n border-bottom-left-radius: 10px;\n}\n\n/*\nfor QRangeSlider: use \"qproperty-barColor\". \"sub-page\" will not work.\n*/\nQRangeSlider {\n qproperty-barColor: #447;\n}\n```\n\n</details>\n\n### macOS\n\n##### Catalina\n![mac10](images/demo_darwin10.png)\n\n##### Big Sur\n![mac11](images/demo_darwin11.png)\n\n### Windows\n\n![window](images/demo_windows.png)\n\n### Linux\n\n![linux](images/demo_linux.png)\n\n\n## Labeled Sliders\n\nThis package also includes two \"labeled\" slider variants. One for `QRangeSlider`, and one for the native `QSlider`:\n\n### `QLabeledRangeSlider`\n\n![labeled_range](images/labeled_range.png)\n\n```python\nfrom qtrangeslider import QLabeledRangeSlider\n```\n\nThis has the same API as `QRangeSlider` with the following additional options:\n\n#### `handleLabelPosition`/`setHandleLabelPosition`\n\nWhere/whether labels are shown adjacent to slider handles.\n\n**type:** `QLabeledRangeSlider.LabelPosition`\n\n**default:** `LabelPosition.LabelsAbove`\n\n*options:*\n\n- `LabelPosition.NoLabel` (no labels shown adjacent to handles)\n- `LabelPosition.LabelsAbove`\n- `LabelPosition.LabelsBelow`\n- `LabelPosition.LabelsRight` (alias for `LabelPosition.LabelsAbove`)\n- `LabelPosition.LabelsLeft` (alias for `LabelPosition.LabelsBelow`)\n\n\n#### `edgeLabelMode`/`setEdgeLabelMode`\n\n**type:** `QLabeledRangeSlider.EdgeLabelMode`\n\n**default:** `EdgeLabelMode.LabelIsRange`\n\n*options:*\n\n- `EdgeLabelMode.NoLabel`: no labels shown at slider extremes\n- `EdgeLabelMode.LabelIsRange`: edge labels shown the min/max values\n- `EdgeLabelMode.LabelIsValue`: edge labels shown the slider range\n\n\n#### fine tuning position of labels:\n\nIf you find that you need to fine tune the position of the handle labels:\n\n- `QLabeledRangeSlider.label_shift_x`: adjust horizontal label position\n- `QLabeledRangeSlider.label_shift_y`: adjust vertical label position\n\n### `QLabeledSlider`\n\n\n![labeled_range](images/labeled_qslider.png)\n\n```python\nfrom qtrangeslider import QLabeledSlider\n```\n\n(no additional options at this point)\n\n## Issues\n\nIf you encounter any problems, please [file an issue] along with a detailed\ndescription.\n\n[file an issue]: https://github.com/tlambert03/QtRangeSlider/issues\n\n\n",
"bugtrack_url": null,
"license": "BSD-3",
"summary": "Multi-handle range slider widget for PyQt/PySide",
"version": "0.1.5",
"project_urls": {
"Changelog": "https://github.com/tlambert03/QtRangeSlider/blob/master/CHANGELOG.md",
"Homepage": "https://github.com/tlambert03/QtRangeSlider",
"Source": "https://github.com/tlambert03/QtRangeSlider",
"Tracker": "https://github.com/tlambert03/QtRangeSlider/issues"
},
"split_keywords": [
"qt",
"range slider",
"widget"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5e7dde073b46b8f1f6f971f71e3ab6062df30613c838e6c12c72acfec4ad3fe2",
"md5": "c47c920735d54bb5a715116d5b509abe",
"sha256": "b716a0b4adffbe9015d3bff44f15312214f2ad411830dba78bc48869c31ba557"
},
"downloads": -1,
"filename": "QtRangeSlider-0.1.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c47c920735d54bb5a715116d5b509abe",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 33225,
"upload_time": "2021-06-13T02:13:12",
"upload_time_iso_8601": "2021-06-13T02:13:12.151709Z",
"url": "https://files.pythonhosted.org/packages/5e/7d/de073b46b8f1f6f971f71e3ab6062df30613c838e6c12c72acfec4ad3fe2/QtRangeSlider-0.1.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f43a2c0ff8c9ca3773e198f4e5921ba81a095ff0910fd8079c19a8bbc0a96080",
"md5": "344fb2537f3e2a267dcadd243f924ec0",
"sha256": "5375df8c31eec80bb4d4c2ac76a842973832560cc0a522c8c5715b8c5f68e213"
},
"downloads": -1,
"filename": "QtRangeSlider-0.1.5.tar.gz",
"has_sig": false,
"md5_digest": "344fb2537f3e2a267dcadd243f924ec0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 238389,
"upload_time": "2021-06-13T02:13:13",
"upload_time_iso_8601": "2021-06-13T02:13:13.159512Z",
"url": "https://files.pythonhosted.org/packages/f4/3a/2c0ff8c9ca3773e198f4e5921ba81a095ff0910fd8079c19a8bbc0a96080/QtRangeSlider-0.1.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2021-06-13 02:13:13",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tlambert03",
"github_project": "QtRangeSlider",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "qtrangeslider"
}