Skip to content

Add feature to allow editing a slider's value outside of its current range - #353

Merged
tlambert03 merged 7 commits into
pyapp-kit:mainfrom
jules-vanaret:label-extents
Oct 16, 2026
Merged

tlambert03 merged 7 commits into
pyapp-kit:mainfrom
jules-vanaret:label-extents

Conversation

@jules-vanaret

@jules-vanaret jules-vanaret commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

PR description

This is a small UX tweak for labeled range sliders.

The problem addressed is that if you edit a slider value label (the text box just above the slider knob) and type a value outside the current slider range, that value gets clamped at the slider bounds. This could be cumbersome for things like contrast-limit controls, where users might expect to be able to type a new endpoint directly instead of first adjusting the min/max edge labels (see napari/napari#9310 ).

Changes

SliderLabel.setValue() normally clamps values to the slider bounds when it refreshes labels. It now accepts a clamp_values parameter, which defaults to True to retain its existing bounds-clamping behavior for normal label updates. SliderLabel._editing_finished() passes clamp_values=False before emitting valueEdited, allowing the owning range slider to receive the raw out-of-range value and decide whether to expand its bounds.

I added an opt-in flag to the range slider itself to trigger the new behaviour:

  • expandRangeOnHandleEdit()
  • setExpandRangeOnHandleEdit(bool)

How to use it in practice

slider = QLabeledRangeSlider() # or QLabeledDoubleRangeSlider()
slider.setExpandRangeOnHandleEdit(True)

With that enabled, typing 110 into the upper handle label will expand the max to 110 and set the handle there instead of being stuck at the old bound.

Reproducer

The small example below illustrates simple- and double-sliders with and without the new range-expansion feature triggered. Try to modify e.g the value of one of the slider above 100 and observe the behavior.

import sys
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget, QLabel
from superqt import QLabeledDoubleRangeSlider, QLabeledRangeSlider


class Reproducer(QWidget):
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout(self)

        self.default_slider = QLabeledRangeSlider()
        self.default_slider.setRange(0, 100)
        self.default_slider.setValue((50,))

        self.default_doubleslider = QLabeledDoubleRangeSlider()
        self.default_doubleslider.setRange(0, 100)
        self.default_doubleslider.setValue((20, 80))

        self.expanding_slider = QLabeledRangeSlider()
        self.expanding_slider.setRange(0, 100)
        self.expanding_slider.setValue((50,))
        self.expanding_slider.setExpandRangeOnHandleEdit(True)

        self.expanding_doubleslider = QLabeledDoubleRangeSlider()
        self.expanding_doubleslider.setRange(0, 100)
        self.expanding_doubleslider.setValue((20, 80))
        self.expanding_doubleslider.setExpandRangeOnHandleEdit(True)

        layout.addWidget(QLabel("This is a simple slider without the new feature:"))
        layout.addWidget(self.default_slider)
        layout.addWidget(QLabel("This is a double slider without the new feature:"))
        layout.addWidget(self.default_doubleslider)
        layout.addWidget(QLabel("This is a simple slider with the new feature:"))
        layout.addWidget(self.expanding_slider)
        layout.addWidget(QLabel("This is a double slider with the new feature:"))
        layout.addWidget(self.expanding_doubleslider)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Reproducer()
    win.show()
    sys.exit(app.exec())

@codecov

codecov Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.92%. Comparing base (42b5710) to head (afaf904).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #353      +/-   ##
==========================================
+ Coverage   84.84%   84.92%   +0.08%     
==========================================
  Files          49       49              
  Lines        3925     3940      +15     
==========================================
+ Hits         3330     3346      +16     
+ Misses        595      594       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jules-vanaret

Copy link
Copy Markdown
Contributor Author

@Czaki @brisvag @psobolewskiPhD would you have input on this ?

@brisvag brisvag left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me, and I like that this is settable and false by default 👍

Comment thread src/superqt/sliders/_labeled.py Resolved

@tlambert03 tlambert03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the PR @jules-vanaret ... still some issues to iron out before we can include this though

Comment thread src/superqt/sliders/_labeled.py Resolved
Comment thread src/superqt/sliders/_labeled.py Resolved
@tlambert03
tlambert03 merged commit 4668c07 into pyapp-kit:main Oct 16, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants