Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from PySide import QtCore, QtGui
- """
- Author: Martin Ponweiser
- Date: February 2015
- License: Public domain
- Extends the PySide Qt4 QSlider class:
- QSliderAbsolutePositioning: allows for directly setting the slider value
- by clicking somewhere on the slider (instead of moving in steps).
- QSliderNonlinear: takes a list of integers and builds a slider that stops
- only at the list values. Tick marks are NOT implemented.
- Please keep in mind that this is a rather hacky implementation best
- suited for prototypes :)
- """
- RANGE_INT = 2147483647
- def value_magnet(val, stops):
- """ This locks only at the list items """
- for ii in range(len(stops)-1):
- sstart = stops[ii]
- sstop = stops[ii+1]
- if sstart <= val <= sstop:
- average = (sstart + sstop) / 2
- if val <= average:
- return ii, sstart
- else:
- return ii+1, sstop
- return 0, val
- class QSliderAbsolutePositioning(QtGui.QSlider):
- def __init__(self, *args):
- super(QSliderAbsolutePositioning, self).__init__(*args)
- self.installEventFilter(self)
- def eventFilter(self, widget, event):
- # HACK to avoid erratic slider movements caused by auto-repeat
- # if mouse button is pressed longer.
- if type(event) == QtCore.QTimerEvent:
- # Skip event altogether
- return True
- return QtGui.QSlider.eventFilter(self, widget, event)
- def position_force(self, event):
- # HACK!
- # event.x works always because only mouse events are overridden.
- value_current = QtGui.QStyle.sliderValueFromPosition(self.minimum(),
- self.maximum(), event.x(), self.width())
- self.setValue(value_current)
- def mousePressEvent(self, event):
- QtGui.QSlider.mousePressEvent(self, event)
- self.position_force(event)
- def mouseMoveEvent(self, event):
- QtGui.QSlider.mouseMoveEvent(self, event)
- self.position_force(event)
- class QSliderNonlinear(QSliderAbsolutePositioning):
- index_changed_signal = QtCore.Signal(int)
- def __init__(self, *args):
- super(QSliderNonlinear, self).__init__(*args)
- self.steps_set([0, 1])
- def steps_set(self, steps_orig_sorted):
- # Here we scale to a range which QSlider likes, namely integers!
- self.steps_orig_sorted = steps_orig_sorted
- range_orig = steps_orig_sorted[-1] - steps_orig_sorted[0]
- self.steps_scaled = [int(((step - steps_orig_sorted[0])*RANGE_INT)
- / range_orig) for step in steps_orig_sorted]
- # Get rid of identical steps.
- self.steps_unique = sorted(list(set(self.steps_scaled)))
- self.setMinimum(self.steps_unique[0])
- self.setMaximum(self.steps_unique[-1])
- self.step_index_current = 0
- self.setValue(self.steps_unique[self.step_index_current])
- self.index_changed_signal.emit(self.orig_index_get())
- def orig_index_get(self):
- """
- 0 2 2 2 8 <- start from end, we want highest index for identical values.
- 1 2 3 4 5
- """
- for ii, vv in enumerate(reversed(self.steps_scaled)):
- if vv == self.value():
- orig_index = (len(self.steps_scaled)-1) - ii
- return orig_index
- # self.value is not in steps_scaled
- return None
- @QtCore.Slot(int)
- def value_set_from_orig_index(self, index):
- """ External slot """
- value = self.steps_scaled[index]
- self.setValue(value)
- def position_force(self, event):
- # HACK!
- value_current = QtGui.QStyle.sliderValueFromPosition(self.minimum(),
- self.maximum(), event.x(), self.width())
- index_new, value_new = value_magnet(value_current, self.steps_unique)
- self.setValue(value_new)
- if index_new != self.step_index_current:
- self.step_index_current = index_new
- self.index_changed_signal.emit(self.orig_index_get())
- def mouseReleaseEvent(self, event):
- QtGui.QSlider.mouseReleaseEvent(self, event)
- self.position_force(event)
- def wheel_step(self, delta):
- if delta >= 0:
- if self.step_index_current >= len(self.steps_unique)-1:
- return
- else:
- self.step_index_current += 1
- self.setValue(self.steps_unique[self.step_index_current])
- else:
- if self.step_index_current == 0:
- return
- else:
- self.step_index_current -= 1
- self.setValue(self.steps_unique[self.step_index_current])
- self.index_changed_signal.emit(self.orig_index_get())
- def wheelEvent(self, event):
- QtGui.QSlider.wheelEvent(self, event)
- self.wheel_step(event.delta())
- @QtCore.Slot(int)
- def test_index_print(x):
- print(x)
- if __name__ == "__main__":
- import math
- app = QtGui.QApplication(sys.argv)
- slider = QSliderNonlinear(QtCore.Qt.Horizontal)
- slider.index_changed_signal.connect(test_index_print)
- steps = [math.log1p(xx) for xx in xrange(30)]
- print(steps)
- slider.steps_set(steps)
- slider.show()
- app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment