【问题标题】:Moving QSlider to Mouse Click Position将 QSlider 移动到鼠标点击位置
【发布时间】:2019-03-12 08:15:48
【问题描述】:

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

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

看着Qt5 documentation

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

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

【问题讨论】:

    标签: python python-3.x pyqt pyqt5 qslider


    【解决方案1】:

    解决方法是计算位置并设置在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_())
    

    【讨论】:

    • 完美运行,谢谢!我遇到的唯一问题是当我调用 __init__ 时,滑块忽略了我传递的任何参数,所以我不得不手动传递方向 setOrientation
    【解决方案2】:

    QSlider 没有这样的功能,所以实现它的唯一方法是编写自定义小部件并覆盖其中的鼠标点击:

    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)
    

    请注意,此代码仅适用于水平滑块。

    【讨论】:

      【解决方案3】:

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

      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
      

      【讨论】:

        【解决方案4】:

        试试这个代码。

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

        【讨论】:

          猜你喜欢
          • 2017-10-22
          • 1970-01-01
          • 2012-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多