我在写小工具的时候,需要一个支持小数的滑动条。
我QSpinBox都找到了QDoubleSpinBox,QSlider愣是没找到对应的东西。
网上有好多对QSlider封装实现QDoubleSlider的文章。
似乎Qt真的没有这个东西,需要我们自行实现。
于是我也封装了一个,用起来没啥问题,遂贴出来,供大家参考。
只要依赖没问题,代码可以直接执行,执行之后的效果大致如下:
代码如下:
import numpy
import sys
import PySide6
import PySide6.QtCore
import PySide6.QtWidgets
from PySide6 import QtWidgets
from typing import Optional
class QDoubleSlider(PySide6.QtWidgets.QSlider):
""""""
# 基于QSlider实现DoubleSlider
# https://blog.csdn.net/weixin_43435307/article/details/111830223
valueChanged = PySide6.QtCore.Signal(float)
def __init_subclass__(cls):
""""""
return super().__init_subclass__()
def __init__(
self,
orientation: PySide6.QtCore.Qt.Orientation,
parent: Optional[PySide6.QtWidgets.QWidget] = None,
) -> None:
""""""
super().__init__(orientation=orientation, parent=parent)
# 以下写法属于无意间找到的, 现记录于此, 我个人不喜欢这种写法, 该写法参考了如下链接:
# https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html#specifying-signals-and-slots-by-method-signature-strings
# PySide6.QtCore.QObject.connect(self, PySide6.QtCore.SIGNAL("valueChanged(int)"), self, PySide6.QtCore.SLOT("valueIntToDouble(int)"))
super().valueChanged.connect(self.valueIntToDouble)
self.__min_value: float = super().minimum()
self.__max_value: float = super().maximum()
self.__once_step: int = super().singleStep()
self.__sync_data()
def setMaximum(self, arg__1: float) -> None:
""""""
self.__max_value = arg__1
self.__sync_data()
def setMinimum(self, arg__1: float) -> None:
""""""
self.__min_value = arg__1
self.__sync_data()
def setRange(self, _min: float, _max: float) -> None:
""""""
self.__min_value = _min
self.__max_value = _max
self.__sync_data()
def setSingleStep(self, val: float) -> None:
""""""
self.__once_step = val
self.__sync_data()
def setValue(self, arg__1: float) -> None:
""""""
PySide6.QtWidgets.QSlider.setValue(
self,
round(pow(10, self.__precision) * arg__1, ndigits=9)
)
@PySide6.QtCore.Slot(int)
def valueIntToDouble(self, value: int):
""""""
val: float = round(pow(10, self.__precision * -1) * value, ndigits=9)
self.valueChanged.emit(val)
@classmethod
def __float_ndigit(cls, val) -> int:
""""""
return len(numpy.format_float_positional(val, precision=9).split(sep='.')[1])
def __sync_data(self) -> None:
""""""
self.__precision: int = max(
self.__float_ndigit(self.__min_value),
self.__float_ndigit(self.__max_value),
self.__float_ndigit(self.__once_step),
)
PySide6.QtWidgets.QSlider.setRange(
self,
round(pow(10, self.__precision) * self.__min_value, ndigits=9),
round(pow(10, self.__precision) * self.__max_value, ndigits=9)
)
PySide6.QtWidgets.QSlider.setSingleStep(
self,
round(pow(10, self.__precision) * self.__once_step, ndigits=9)
)
@classmethod
def _test(cls) -> None:
""""""
qapp = QtWidgets.QApplication.instance()
if qapp is None:
qapp: QtWidgets.QApplication = QtWidgets.QApplication(sys.argv)
is_custom: bool = True
slider = QDoubleSlider(PySide6.QtCore.Qt.Horizontal) if is_custom else PySide6.QtWidgets.QSlider(PySide6.QtCore.Qt.Horizontal)
print("current: slider,type :", type(slider))
print("default: slider.minimum :", slider.minimum())
print("default: slider.maximum :", slider.maximum())
print("default: slider.singleStep:", slider.singleStep())
slider.setRange(0.5, 1.5)
slider.setSingleStep(0.1)
slider.valueChanged.connect(lambda _: print(_))
slider.show()
qapp.exec()
if __name__ == "__main__":
QDoubleSlider._test()
。