class RangeFilter(QtGui.QWidget): def __init__(self, *args): super(RangeFilter, self).__init__(*args) self._createSpinBoxes() self.connect(self.minSpin, QtCore.SIGNAL("editingFinished()"), self._released) self.connect(self.maxSpin, QtCore.SIGNAL("editingFinished()"), self._released) self._createSlider() self.connect(self.slider, QtCore.SIGNAL("sliderReleased()"), self._released) #self.setMinimum( 0 ) #self.setLowValue( 0 ) #self.setMaximum( 100 ) #self.setHighValue( 100 ) self.recreateUi() def _createSpinBoxes(self): self.minSpin = QtGui.QSpinBox(self) self.maxSpin = QtGui.QSpinBox(self) self.connect(self.minSpin, QtCore.SIGNAL("valueChanged(int)"), self.setLowValue) self.connect(self.maxSpin, QtCore.SIGNAL("valueChanged(int)"), self.setHighValue) def _createSlider(self): self.slider = RangeSlider(self) self.connect(self.slider, QtCore.SIGNAL("sliderMoved(int)"), self._moved) def recreateUi(self): layout = self.layout() if not layout: layout = QtGui.QGridLayout(self) layout.setMargin(0) self.setLayout(layout) else: layout.removeWidget(self.maxSpin) layout.removeWidget(self.slider) layout.removeWidget(self.minSpin) if self.slider.orientation() == QtCore.Qt.Horizontal: layout.addWidget(self.minSpin, 0, 0) layout.addWidget(self.slider, 0, 1) layout.addWidget(self.maxSpin, 0, 2) self.slider.setMinimumSize(QtCore.QSize(30, 0)) else: layout.addWidget(self.maxSpin, 0, 0) layout.addWidget(self.slider, 1, 0) layout.addWidget(self.minSpin, 2, 0) self.slider.setMinimumSize(QtCore.QSize(0, 30)) def orientation(self): return self.slider.orientation() def setOrientation(self, val): self.slider.setOrientation(val) self.recreateUi() def isActive(self): if self.lowValue() > self.minimum(): return True if self.highValue() < self.maximum(): return True return False def checkValue(self, val): val = self._getValue(val) if val is None: return False return val >= self._getValue( self.lowValue()) and val <= self._getValue(self.highValue()) def _toSliderValue(self, val): return val def _fromSliderValue(self, val): return val def minimum(self): return self.minSpin.minimum() def maximum(self): return self.maxSpin.maximum() def setMinimum(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) self.minSpin.setMinimum(val) self.maxSpin.setMinimum(val) self.slider.setMinimum(self._toSliderValue(val)) def setMaximum(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) self.minSpin.setMaximum(val) self.maxSpin.setMaximum(val) self.slider.setMaximum(self._toSliderValue(val)) # avoid resizing when the max value changes minSpinSize = self.minSpin.sizeHint() maxSpinSize = self.maxSpin.sizeHint() w, h = max(minSpinSize.width(), maxSpinSize.width()), max(minSpinSize.height(), maxSpinSize.height()) self.minSpin.setFixedSize(w, h) self.maxSpin.setFixedSize(w, h) def lowValue(self): return self.minSpin.value() def highValue(self): return self.maxSpin.value() def setLowValue(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) minVal = self._getValue(self.minimum()) if val < minVal: val = minVal if val == self._getValue(self.lowValue()): return self.minSpin.blockSignals(True) self.slider.blockSignals(True) self.minSpin.setValue(val) self.maxSpin.setMinimum(val) self.slider.setLowValue(self._toSliderValue(val)) self.minSpin.blockSignals(False) self.slider.blockSignals(False) self.emit(QtCore.SIGNAL("lowValueChanged"), val) def setHighValue(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) maxVal = self._getValue(self.maximum()) if val > maxVal: val = maxVal if val == self._getValue(self.highValue()): return self.maxSpin.blockSignals(True) self.slider.blockSignals(True) self.maxSpin.setValue(val) self.minSpin.setMaximum(val) self.slider.setHighValue(self._toSliderValue(val)) self.maxSpin.blockSignals(False) self.slider.blockSignals(False) self.emit(QtCore.SIGNAL("highValueChanged"), val) def _updateValues(self): # avoid multiple signals when values don't change if hasattr(self, '_lastLowValueOnReleased') and hasattr( self, '_lastHighValueOnReleased'): if self._lastLowValueOnReleased == self.lowValue( ) and self._lastHighValueOnReleased == self.highValue(): return False self._lastLowValueOnReleased = self.lowValue() self._lastHighValueOnReleased = self.highValue() return True def _moved(self, *args): self._sliderLowValueChanged(self.slider.lowValue()) self._sliderHighValueChanged(self.slider.highValue()) self.emit(QtCore.SIGNAL("valuesChanged"), self.lowValue(), self.highValue()) def _released(self, *args): if not self._updateValues(): return # do not emit the signal now, wait the event loop QtCore.QTimer.singleShot(0, self._onChangeFinished) def _onChangeFinished(self): self.emit(QtCore.SIGNAL("changeFinished"), self._lastLowValueOnReleased, self._lastHighValueOnReleased) def _sliderLowValueChanged(self, val): self.setLowValue(self._fromSliderValue(val)) def _sliderHighValueChanged(self, val): self.setHighValue(self._fromSliderValue(val)) @classmethod def _getValue(self, value): if not isinstance(value, QtCore.QVariant): return value if not value.isValid(): return val, ok = value.toInt() if ok: return val return int(float(value.toString()))
class RangeFilter(QtGui.QWidget): """ A widget to select int ranges. It displays a RangeSlider between two QSpinbox widgets. @emit lowValueChanged signal when the low value is changed @emit highValueChanged signal when the high value is changed @emit valuesChanged signal when either the low or high value is changed @emit changeFinished signal when the slider is released in a new position or the spinboxes editing finished """ def __init__(self, *args): super(RangeFilter, self).__init__(*args) self._createSpinBoxes() self.connect( self.minSpin, QtCore.SIGNAL("editingFinished()"), self._released ) self.connect( self.maxSpin, QtCore.SIGNAL("editingFinished()"), self._released ) self._createSlider() self.connect( self.slider, QtCore.SIGNAL("sliderReleased()"), self._released ) #self.setMinimum( 0 ) #self.setLowValue( 0 ) #self.setMaximum( 100 ) #self.setHighValue( 100 ) self._updateUi() def _createSpinBoxes(self): self.minSpin = QtGui.QSpinBox(self) self.maxSpin = QtGui.QSpinBox(self) self.connect( self.minSpin, QtCore.SIGNAL("valueChanged(int)"), self.setLowValue ) self.connect( self.maxSpin, QtCore.SIGNAL("valueChanged(int)"), self.setHighValue ) def _createSlider(self): self.slider = RangeSlider(self) self.connect( self.slider, QtCore.SIGNAL("sliderMoved(int)"), self._moved ) def _updateUi(self): layout = self.layout() if not layout: layout = QtGui.QGridLayout(self) layout.setMargin(0) self.setLayout( layout ) else: layout.removeWidget(self.maxSpin) layout.removeWidget(self.slider) layout.removeWidget(self.minSpin) if self.slider.orientation() == QtCore.Qt.Horizontal: layout.addWidget(self.minSpin, 0, 0) layout.addWidget(self.slider, 0, 1) layout.addWidget(self.maxSpin, 0, 2) self.slider.setMinimumSize(QtCore.QSize(30, 0)) else: layout.addWidget(self.maxSpin, 0, 0) layout.addWidget(self.slider, 1, 0) layout.addWidget(self.minSpin, 2, 0) self.slider.setMinimumSize(QtCore.QSize(0, 30)) def orientation(self): """ Get the widget orientation. """ return self.slider.orientation() def setOrientation(self, val): """ Set the widget orientation. """ self.slider.setOrientation( val ) self._updateUi() def isActive(self): """ Check if the filter widget has low or high values different from respectively the mininimum and maximum values. @returns True if low value is greather than the minimum OR the high value is less than the maximum, False otherwise """ return self.lowValue() > self.minimum() or self.highValue() < self.maximum() def checkValue(self, val): """ Check if val is within the range [min, max]. @returns True if val is in the range, False otherwise """ val = self._getValue(val) if val is None: return False return val >= self._getValue( self.lowValue() ) and val <= self._getValue( self.highValue() ) def _toSliderValue(self, val): return val def _fromSliderValue(self, val): return val def minimum(self): """ Get the minimum value. """ return self.minSpin.minimum() def maximum(self): """ Get the maximum value. """ return self.maxSpin.maximum() def setMinimum(self, value): """ Set the minimum value. """ val = self._getValue( value ) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) self.minSpin.setMinimum(val) self.maxSpin.setMinimum(val) self.slider.setMinimum( self._toSliderValue(val) ) def setMaximum(self, value): """ Set the maximum value. """ val = self._getValue( value ) if val is None: raise TypeError("invalid type for '%s'" % repr(value) ) self.minSpin.setMaximum(val) self.maxSpin.setMaximum(val) self.slider.setMaximum( self._toSliderValue(val) ) # avoid resizing when the max value changes minSpinSize = self.minSpin.sizeHint() maxSpinSize = self.maxSpin.sizeHint() w,h = max(minSpinSize.width(), maxSpinSize.width()), max(minSpinSize.height(), maxSpinSize.height()) self.minSpin.setFixedSize( w, h ) self.maxSpin.setFixedSize( w, h ) def lowValue(self): return self.minSpin.value() def highValue(self): return self.maxSpin.value() def setLowValue(self, value): """ Set the low value. """ val = self._getValue( value ) if val is None: raise TypeError("invalid type for '%s'" % repr(value) ) minVal = self._getValue( self.minimum() ) if val < minVal: val = minVal if val == self._getValue( self.lowValue() ): return self.minSpin.blockSignals(True) self.slider.blockSignals(True) self.minSpin.setValue( val ) self.maxSpin.setMinimum( val ) self.slider.setLowValue( self._toSliderValue(val) ) self.minSpin.blockSignals(False) self.slider.blockSignals(False) self.emit( QtCore.SIGNAL("lowValueChanged"), val ) def setHighValue(self, value): """ Set the high value. """ val = self._getValue( value ) if val is None: raise TypeError("invalid type for '%s'" % repr(value) ) maxVal = self._getValue(self.maximum()) if val > maxVal: val = maxVal if val == self._getValue(self.highValue()): return self.maxSpin.blockSignals(True) self.slider.blockSignals(True) self.maxSpin.setValue( val ) self.minSpin.setMaximum( val ) self.slider.setHighValue( self._toSliderValue(val) ) self.maxSpin.blockSignals(False) self.slider.blockSignals(False) self.emit( QtCore.SIGNAL("highValueChanged"), val ) def _updateValues(self): # avoid multiple signals when values don't change if hasattr(self, '_lastLowValueOnReleased') and hasattr(self, '_lastHighValueOnReleased'): if self._lastLowValueOnReleased == self.lowValue() and self._lastHighValueOnReleased == self.highValue(): return False self._lastLowValueOnReleased = self.lowValue() self._lastHighValueOnReleased = self.highValue() return True def _moved(self, *args): self._sliderLowValueChanged(self.slider.lowValue()) self._sliderHighValueChanged(self.slider.highValue()) self.emit( QtCore.SIGNAL("valuesChanged"), self.lowValue(), self.highValue() ) def _released(self, *args): if not self._updateValues(): return # do not emit the signal now, wait the event loop QtCore.QTimer.singleShot(0, self._onChangeFinished) def _onChangeFinished(self): self.emit( QtCore.SIGNAL("changeFinished"), self._lastLowValueOnReleased, self._lastHighValueOnReleased ) def _sliderLowValueChanged(self, val): self.setLowValue( self._fromSliderValue(val) ) def _sliderHighValueChanged(self, val): self.setHighValue( self._fromSliderValue(val) ) @classmethod def _getValue(self, value): if not isinstance(value, QtCore.QVariant): return value if not value.isValid(): return val, ok = value.toInt() if ok: return val return int(float(value.toString()))
class RangeFilter(QtGui.QWidget): def __init__(self, *args): super(RangeFilter, self).__init__(*args) self._createSpinBoxes() self.connect(self.minSpin, QtCore.SIGNAL("editingFinished()"), self._released) self.connect(self.maxSpin, QtCore.SIGNAL("editingFinished()"), self._released) self._createSlider() self.connect(self.slider, QtCore.SIGNAL("sliderReleased()"), self._released) self.recreateUi() def _createSpinBoxes(self): self.minSpin = QtGui.QSpinBox(self) self.maxSpin = QtGui.QSpinBox(self) self.connect(self.minSpin, QtCore.SIGNAL("valueChanged(int)"), self.setLowValue) self.connect(self.maxSpin, QtCore.SIGNAL("valueChanged(int)"), self.setHighValue) def _createSlider(self): self.slider = RangeSlider(self) self.connect(self.slider, QtCore.SIGNAL("sliderMoved(int)"), self._moved) def recreateUi(self): layout = self.layout() if not layout: layout = QtGui.QGridLayout(self) layout.setMargin(0) self.setLayout(layout) else: layout.removeWidget(self.maxSpin) layout.removeWidget(self.slider) layout.removeWidget(self.minSpin) if self.slider.orientation() == QtCore.Qt.Horizontal: layout.addWidget(self.minSpin, 0, 0) layout.addWidget(self.slider, 0, 1) layout.addWidget(self.maxSpin, 0, 2) self.slider.setMinimumSize(QtCore.QSize(30, 0)) else: layout.addWidget(self.maxSpin, 0, 0) layout.addWidget(self.slider, 1, 0) layout.addWidget(self.minSpin, 2, 0) self.slider.setMinimumSize(QtCore.QSize(0, 30)) def orientation(self): return self.slider.orientation() def setOrientation(self, val): self.slider.setOrientation(val) self.recreateUi() def isActive(self): if self.lowValue() > self.minimum(): return True if self.highValue() < self.maximum(): return True return False def checkValue(self, val): val = self._getValue(val) if val is None: return False return (self._getValue(self.lowValue()) <= val <= self._getValue(self.highValue())) def _toSliderValue(self, val): return val def _fromSliderValue(self, val): return val def minimum(self): return self.minSpin.minimum() def maximum(self): return self.maxSpin.maximum() def setMinimum(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) self.minSpin.setMinimum(val) self.maxSpin.setMinimum(val) self.slider.setMinimum(self._toSliderValue(val)) def setMaximum(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) self.minSpin.setMaximum(val) self.maxSpin.setMaximum(val) self.slider.setMaximum(self._toSliderValue(val)) # avoid resizing when the max value changes minSpinSize = self.minSpin.sizeHint() maxSpinSize = self.maxSpin.sizeHint() w, h = max(minSpinSize.width(), maxSpinSize.width()), max( minSpinSize.height(), maxSpinSize.height()) self.minSpin.setFixedSize(w, h) self.maxSpin.setFixedSize(w, h) def lowValue(self): return self.minSpin.value() def highValue(self): return self.maxSpin.value() def setLowValue(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) minVal = self._getValue(self.minimum()) if val < minVal: val = minVal if val == self._getValue(self.lowValue()): return self.minSpin.blockSignals(True) self.slider.blockSignals(True) self.minSpin.setValue(val) self.maxSpin.setMinimum(val) self.slider.setLowValue(self._toSliderValue(val)) self.minSpin.blockSignals(False) self.slider.blockSignals(False) self.emit(QtCore.SIGNAL("lowValueChanged"), val) def setHighValue(self, value): val = self._getValue(value) if val is None: raise TypeError("invalid type for '%s'" % repr(value)) maxVal = self._getValue(self.maximum()) if val > maxVal: val = maxVal if val == self._getValue(self.highValue()): return self.maxSpin.blockSignals(True) self.slider.blockSignals(True) self.maxSpin.setValue(val) self.minSpin.setMaximum(val) self.slider.setHighValue(self._toSliderValue(val)) self.maxSpin.blockSignals(False) self.slider.blockSignals(False) self.emit(QtCore.SIGNAL("highValueChanged"), val) def _updateValues(self): # avoid multiple signals when values don't change if hasattr(self, '_lastLowValueOnReleased') and \ hasattr(self, '_lastHighValueOnReleased'): if self._lastLowValueOnReleased == self.lowValue() and \ self._lastHighValueOnReleased == self.highValue(): return False self._lastLowValueOnReleased = self.lowValue() self._lastHighValueOnReleased = self.highValue() return True def _moved(self, *args): self._sliderLowValueChanged(self.slider.lowValue()) self._sliderHighValueChanged(self.slider.highValue()) self.emit(QtCore.SIGNAL("valuesChanged"), self.lowValue(), self.highValue()) def _released(self, *args): if not self._updateValues(): return # do not emit the signal now, wait the event loop QtCore.QTimer.singleShot(0, self._onChangeFinished) def _onChangeFinished(self): self.emit(QtCore.SIGNAL("changeFinished"), self._lastLowValueOnReleased, self._lastHighValueOnReleased) def _sliderLowValueChanged(self, val): self.setLowValue(self._fromSliderValue(val)) def _sliderHighValueChanged(self, val): self.setHighValue(self._fromSliderValue(val)) @classmethod def _getValue(cls, value): return value