Created
July 8, 2019 10:26
-
-
Save wiccy46/b7d8a1d57626a4ea40b19c5dbc5029ff to your computer and use it in GitHub Desktop.
[label_slider]Pyqt5 Label slider. This create text ticks alongside qt slider #python #qt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from PyQt5.QtGui import QPainter, QPen, QFont | |
from PyQt5.QtWidgets import QAbstractButton, QSlider, QWidget, QVBoxLayout, QHBoxLayout,\ | |
QStyleOptionSlider, QStyle | |
from PyQt5.QtCore import Qt, QRect, QPoint | |
import numpy as np | |
class LabeledSlider(QWidget): | |
def __init__(self, minimum, maximum, interval=1, orientation=Qt.Horizontal, | |
labels=None, p0=0, parent=None): | |
super(LabeledSlider, self).__init__(parent=parent) | |
levels=range(minimum, maximum + interval, interval) | |
if labels is not None: | |
if not isinstance(labels, (tuple, list)): | |
raise Exception("<labels> is a list or tuple.") | |
if len(labels) != len(levels): | |
raise Exception("Size of <labels> doesn't match levels.") | |
self.levels=list(zip(levels,labels)) | |
else: | |
self.levels=list(zip(levels,map(str,levels))) | |
if orientation==Qt.Horizontal: | |
self.layout=QVBoxLayout(self) | |
elif orientation==Qt.Vertical: | |
self.layout=QHBoxLayout(self) | |
else: | |
raise Exception("<orientation> wrong.") | |
# gives some space to print labels | |
self.left_margin=10 | |
self.top_margin=10 | |
self.right_margin=10 | |
self.bottom_margin=10 | |
self.layout.setContentsMargins(self.left_margin,self.top_margin, | |
self.right_margin,self.bottom_margin) | |
self.sl=QSlider(orientation, self) | |
self.sl.setMinimum(minimum) | |
self.sl.setMaximum(maximum) | |
self.sl.setValue(minimum) | |
self.sl.setSliderPosition(p0) | |
if orientation==Qt.Horizontal: | |
self.sl.setTickPosition(QSlider.TicksBelow) | |
self.sl.setMinimumWidth(300) # just to make it easier to read | |
else: | |
self.sl.setTickPosition(QSlider.TicksLeft) | |
self.sl.setMinimumHeight(300) # just to make it easier to read | |
self.sl.setTickInterval(interval) | |
self.sl.setSingleStep(1) | |
self.layout.addWidget(self.sl) | |
def paintEvent(self, e): | |
super(LabeledSlider,self).paintEvent(e) | |
style=self.sl.style() | |
painter=QPainter(self) | |
st_slider=QStyleOptionSlider() | |
st_slider.initFrom(self.sl) | |
st_slider.orientation=self.sl.orientation() | |
length=style.pixelMetric(QStyle.PM_SliderLength, st_slider, self.sl) | |
available=style.pixelMetric(QStyle.PM_SliderSpaceAvailable, st_slider, self.sl) | |
for v, v_str in self.levels: | |
# get the size of the label | |
rect=painter.drawText(QRect(), Qt.TextDontPrint, v_str) | |
if self.sl.orientation()==Qt.Horizontal: | |
# I assume the offset is half the length of slider, therefore | |
# + length//2 | |
x_loc=QStyle.sliderPositionFromValue(self.sl.minimum(), | |
self.sl.maximum(), v, available)+length//2 | |
# left bound of the text = center - half of text width + L_margin | |
left=x_loc-rect.width()//2+self.left_margin | |
bottom=self.rect().bottom() | |
# enlarge margins if clipping | |
if v==self.sl.minimum(): | |
if left<=0: | |
self.left_margin=rect.width()//2-x_loc | |
if self.bottom_margin<=rect.height(): | |
self.bottom_margin=rect.height() | |
self.layout.setContentsMargins(self.left_margin, | |
self.top_margin, self.right_margin, | |
self.bottom_margin) | |
if v==self.sl.maximum() and rect.width()//2>=self.right_margin: | |
self.right_margin=rect.width()//2 | |
self.layout.setContentsMargins(self.left_margin, | |
self.top_margin, self.right_margin, | |
self.bottom_margin) | |
else: | |
y_loc=QStyle.sliderPositionFromValue(self.sl.minimum(), | |
self.sl.maximum(), v, available, upsideDown=True) | |
bottom=y_loc+length//2+rect.height()//2+self.top_margin-3 | |
# there is a 3 px offset that I can't attribute to any metric | |
left=self.left_margin-rect.width() | |
if left<=0: | |
self.left_margin=rect.width()+2 | |
self.layout.setContentsMargins(self.left_margin, | |
self.top_margin, self.right_margin, | |
self.bottom_margin) | |
pos=QPoint(left, bottom) | |
painter.drawText(pos, v_str) | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment