PyQt5 QSlider 根据滑块移动的方向关闭一个

PyQt5 QSlider is off by one depending on which direction the slider is moved

我在使用 PyQt5 中的 QSlider 元素时遇到问题。下面是我的代码的简化版本,它只调用滑块。我有两种方法:一种是在滑块移动时打印滑块值,另一种是在用户释放按钮后打印滑块值。

如果您将滑块拖动到某个位置(假设为 10)并保持住,它应该打印出 10。如果您松开它,它将打印出 11(如果您从左侧拖动)否则它将打印出 9(如果您从右侧拖动。

我真的很困惑为什么它会根据滑块移动的方向而偏移 1。我希望这两种方法打印出相同的数字。

from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QSlider
from PyQt5.QtCore import Qt
import sys


class GUIWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(300, 0, 900, 900)

        # Slider
        self.eventSlider = QSlider(Qt.Horizontal)
        self.eventSlider.setFixedWidth(600)
        self.eventSlider.setSingleStep(1)
        self.eventSlider.setValue(0)
        self.eventSlider.setMinimum(0)
        self.eventSlider.setMaximum(20)
        self.eventSlider.setTickInterval(1)
        self.eventSlider.setTickPosition(QSlider.TicksBelow)
        self.eventSlider.sliderMoved.connect(self.slider_changing)
        self.eventSlider.sliderReleased.connect(self.slider_changed)

        GUILayout = QGridLayout()
        GUILayout.setContentsMargins(0, 0, 0, 0)
        GUILayout.addWidget(self.eventSlider, 0, 0, 1, 9, alignment=Qt.AlignCenter)
        self.setLayout(GUILayout)

    def slider_changing(self):
        print(self.eventSlider.value())

    def slider_changed(self):
        print(self.eventSlider.value())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = GUIWindow()
    window.show()
    sys.exit(app.exec_())

您对 QAbstractSlider 的机制感到困惑(这是 QSlider 等小部件的基础class)。

看看文档中的解释吧

QAbstractSlider.sliderMoved(value):

This signal is emitted when sliderDown is true and the slider moves. This usually happens when the user is dragging the slider. The value is the new slider position.

QAbstractSlider.valueChanged(value)

This signal is emitted when the slider value has changed, with the new slider value as argument.

区别在于sliderMoved信号是在滑块移动时发出的,不是当值改变时。
事实上,如果禁用 tracking,您会看到 slider_changing 将始终打印 same current值,直到释放滑块。

这就是禁用跟踪(默认)时发生的情况:

  • 滑块在 0
  • 你把鼠标按在手柄上
  • sliderPressed被发出,此时值和位置还是一样,0
  • 你将手柄移动一步
  • sliderMoved信号发出,现在滑块位置为1,但数值仍为0
  • 滑块绘制在新位置
  • 滑块 "realizes" 跟踪被禁用,所以 现在 它更新 当前
  • 发出valueChanged信号

由于您正在检查 sliderMoved 信号连接中的 currentValue,此时该值尚未更新。

要在移动滑块时获取实际值,您有两个选择:

  • 使用 sliderPosition() 而不是 currentValue(或者,更好的是,获取 sliderMoved 的参数,它已经包含新位置(以及可能的新值,无论跟踪是否启用与否);
  • 连接到 valueChanged()