7

我有一个 QSlider,当用户按下鼠标左键时,我想将其移动到鼠标光标的位置。我一直在四处寻找,找不到任何最近的东西并解决了我的问题。

进度条

这是我的滑块。我希望能够单击以使滑块跳到鼠标单击的位置。我可以拖动滑块,但我希望能够单击。我测试了单击 Dolphin 文件管理器中的滑块。它增加而不是跳到鼠标的确切位置。

查看Qt5 文档

QSlider 很少有自己的功能 [...]

这表明没有内置的方法可以做到这一点。有没有办法获得鼠标单击的位置并将滑块移动到该点?

4

4 回答 4

8

解决方法是计算位置并设置在mousePressEvent中,因为它取决于每个操作系统的样式和样式表,所以计算不像算术计算那样容易,所以我们必须使用QStyle,如下所示:

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_())
于 2018-10-07T15:25:53.557 回答
3

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.

于 2018-10-07T15:17:50.130 回答
1

我相信我有一个更少涉及的解决方案:

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())

然后确保连接到您正在更新的任何内容,如下所示:

# 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
于 2021-10-11T21:15:47.837 回答
0

试试这个代码。

class MySliderStyle : public QProxyStyle
{
public:
    virtual int styleHint(StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0) const{
        if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
        {
            return Qt::LeftButton;
        }
        else
        {
            return QProxyStyle::styleHint(hint, option, widget, returnData);
        }
  }
};


ui->mySlider->setStyle(new MySliderStyle);
于 2022-01-17T13:09:15.623 回答