Moving QSlider To Mouse Click Position
I have a QSlider that I want to move to the position of the mouse cursor when the user presses the left mouse button. I've been hunting around and couldn't find anything that was r
Solution 1:
The solution is to make a calculation of the position and set it in the mousePressEvent, the calculation is not easy as an arithmetic calculation since it depends on the style of each OS and the stylesheet so we must use QStyle as shown below:
from PyQt5 import QtCore, QtWidgets
class Slider(QtWidgets.QSlider):
def mousePressEvent(self, event):
super(Slider, self).mousePressEvent(event)
if event.button() == QtCore.Qt.LeftButton:
val = self.pixelPosToRangeValue(event.pos())
self.setValue(val)
def pixelPosToRangeValue(self, pos):
opt = QtWidgets.QStyleOptionSlider()
self.initStyleOption(opt)
gr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderGroove, self)
sr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)
if self.orientation() == QtCore.Qt.Horizontal:
sliderLength = sr.width()
sliderMin = gr.x()
sliderMax = gr.right() - sliderLength + 1
else:
sliderLength = sr.height()
sliderMin = gr.y()
sliderMax = gr.bottom() - sliderLength + 1;
pr = pos - sr.center() + sr.topLeft()
p = pr.x() if self.orientation() == QtCore.Qt.Horizontal else pr.y()
return QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), p - sliderMin,
sliderMax - sliderMin, opt.upsideDown)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
flay = QtWidgets.QFormLayout(w)
w1 = QtWidgets.QSlider(QtCore.Qt.Horizontal)
w2 = Slider(QtCore.Qt.Horizontal)
flay.addRow("default: ", w1)
flay.addRow("modified: ", w2)
w.show()
sys.exit(app.exec_())
Solution 2:
QSlider
doesn't have such feature so the only way to implepent this is write custom widget and override mouse click in it:
class Slider(QSlider):
def mousePressEvent(self, e):
if e.button() == Qt.LeftButton:
e.accept()
x = e.pos().x()
value = (self.maximum() - self.minimum()) * x / self.width() + self.minimum()
self.setValue(value)
else:
return super().mousePressEvent(self, e)
Note that this code will work for horizontal slider only.
Solution 3:
I believe I have a much less involved solution:
from PyQt5.QtWidgets import QSlider
class ClickSlider(QSlider):
"""A slider with a signal that emits its position when it is pressed. Created to get around the slider only updating when the handle is dragged, but not when a new position is clicked"""
sliderPressedWithValue = QSignal(int)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sliderPressed.connect(self.on_slider_pressed)
def on_slider_pressed(self):
"""emits a more descriptive signal when pressed (with slider value during the press event)"""
self.sliderPressedWithValue.emit(self.value())
And then just make sure to connect to whatever you're updating like this:
# example if you're updating a QMediaPlayer object
from PyQt5.QtMultimedia import QMediaPlayer
player = QMediaPlayer()
slider = ClickSlider()
slider.sliderPressedWithValue.connect(player.setPosition) # updates on click
slider.sliderMoved.connect(player.setPosition) # updates on drag
Post a Comment for "Moving QSlider To Mouse Click Position"