鱼C论坛

 找回密码
 立即注册
查看: 617|回复: 1

pyqt5 QSlider实现数轴但无法在数轴下方显示坐标对应的数值

[复制链接]
发表于 2024-9-17 22:19:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
做了个用QSlider实现[-10,10]的数轴类,但是并不能实现数轴下方显示对应的整数。
求修正与优化其中这一段负责显示数轴下方的整数的代码:
            text = str(value)
            font_metrics = painter.fontMetrics()
            text_width = font_metrics.width(text)
            painter.drawText(x - text_width // 2, slider_height - 30, text)

这一段代码真不知道如何改。。尝试减少了数轴显示的数字的数量也依旧不能显示。不知如何解决

附上全部代码:
  1. import sys
  2. from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSlider, QApplication
  3. from PyQt5.QtCore import Qt
  4. from PyQt5.QtGui import QPainter, QFontMetrics

  5. class NumberLineSlider(QSlider):
  6.     def __init__(self, min_value, max_value, *args, **kwargs):
  7.         super().__init__(Qt.Horizontal, *args, **kwargs)
  8.         self.min_value = min_value
  9.         self.max_value = max_value
  10.         self.setMinimum(min_value)
  11.         self.setMaximum(max_value)
  12.         self.setTickPosition(QSlider.TicksBelow)
  13.         self.setTickInterval(1)  # 设置每个刻度的间隔为1

  14.     def paintEvent(self, event):
  15.         super().paintEvent(event)
  16.         painter = QPainter(self)
  17.         painter.setRenderHint(QPainter.Antialiasing)

  18.         # 获取当前slider的大小
  19.         slider_width = self.width()
  20.         slider_height = self.height()

  21.         # 绘制每个整数标记
  22.         for value in range(self.min_value, self.max_value + 1):
  23.             # 计算每个数值的位置
  24.             x = self.position_for_value(value, slider_width)
  25.             # 绘制刻度线
  26.             painter.drawLine(x, slider_height - 20, x, slider_height - 10)
  27.             
  28.             # 绘制数值文本
  29.             text = str(value)
  30.             font_metrics = painter.fontMetrics()
  31.             text_width = font_metrics.width(text)
  32.             painter.drawText(x - text_width // 2, slider_height - 30, text)

  33.     def position_for_value(self, value, slider_width):
  34.         """计算给定数值在滑块上的 x 坐标"""
  35.         slider_min = self.minimum()
  36.         slider_max = self.maximum()
  37.         # 计算数值相对slider宽度的位置
  38.         return int((value - slider_min) / (slider_max - slider_min) * (slider_width - 20)) + 10

  39. class MainWindow(QWidget):
  40.     def __init__(self):
  41.         super().__init__()

  42.         # 设置数轴范围,从 -10 到 10
  43.         self.slider = NumberLineSlider(-10, 10)
  44.         self.label = QLabel("Move the slider to see the value")

  45.         # 当滑块移动时,更新标签显示的值
  46.         self.slider.valueChanged.connect(self.on_slider_value_changed)

  47.         # 布局
  48.         layout = QVBoxLayout()
  49.         layout.addWidget(self.slider)
  50.         layout.addWidget(self.label)
  51.         self.setLayout(layout)

  52.     def on_slider_value_changed(self, value):
  53.         # 更新标签显示当前滑块值
  54.         self.label.setText(f"Value: {value}")

  55. if __name__ == "__main__":
  56.     app = QApplication(sys.argv)
  57.     window = MainWindow()
  58.     window.show()
  59.     sys.exit(app.exec_())
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-9-17 22:24:22 | 显示全部楼层
看你的代码,主要的问题在于计算 QSlider 的数值位置和进行drawText操作的地方。这里给你一个修正和优化的版本,希望能帮助你解决问题。

  1. import sys
  2. from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSlider, QApplication
  3. from PyQt5.QtCore import Qt
  4. from PyQt5.QtGui import QPainter, QFontMetrics

  5. class NumberLineSlider(QSlider):
  6.     def __init__(self, min_value, max_value, *args, **kwargs):
  7.         super().__init__(Qt.Horizontal, *args, **kwargs)
  8.         self.min_value = min_value
  9.         self.max_value = max_value
  10.         self.setMinimum(min_value)
  11.         self.setMaximum(max_value)
  12.         self.setTickPosition(QSlider.TicksBelow)
  13.         self.setTickInterval(1)  # 设置每个刻度的间隔为1
  14.    
  15.     def paintEvent(self, event):
  16.         super().paintEvent(event)
  17.         painter = QPainter(self)
  18.         painter.setRenderHint(QPainter.Antialiasing)
  19.         
  20.         slider_width = self.width()
  21.         slider_height = self.height()
  22.         
  23.         for value in range(self.min_value, self.max_value + 1):
  24.             x = self.position_for_value(value, slider_width)
  25.             painter.drawLine(x, slider_height - 20, x, slider_height - 10)
  26.             
  27.             text = str(value)
  28.             font_metrics = painter.fontMetrics()
  29.             text_width = font_metrics.horizontalAdvance(text)  # 更新点:使用 horizontalAdvance 而不是 width
  30.             painter.drawText(x - text_width // 2, slider_height - 30, text)
  31.    
  32.     def position_for_value(self, value, slider_width):
  33.         """计算给定数值在滑块上的 x 坐标"""
  34.         slider_min = self.minimum()
  35.         slider_max = self.maximum()
  36.         if slider_max == slider_min:
  37.             return 0
  38.         return int(slider_width * (value - slider_min) / (slider_max - slider_min))

  39. # 主窗口
  40. class MainWindow(QWidget):
  41.     def __init__(self):
  42.         super().__init__()
  43.         self.setWindowTitle('Number Line Slider Example')
  44.         self.setGeometry(100, 100, 600, 100)
  45.         
  46.         layout = QVBoxLayout()
  47.         
  48.         self.slider = NumberLineSlider(0, 10)
  49.         layout.addWidget(self.slider)
  50.         
  51.         self.value_label = QLabel("0")
  52.         layout.addWidget(self.value_label)
  53.         
  54.         self.slider.valueChanged.connect(self.update_label)
  55.         
  56.         self.setLayout(layout)
  57.         
  58.     def update_label(self, value):
  59.         self.value_label.setText(str(value))

  60. if __name__ == "__main__":
  61.     app = QApplication(sys.argv)
  62.     window = MainWindow()
  63.     window.show()
  64.     sys.exit(app.exec_())
复制代码


主要修改点:
1. 使用 `font_metrics.horizontalAdvance(text)` 而不是 `font_metrics.width(text)`。`horizontalAdvance` 是计算字符串显示长度的更现代化方法。
2. 增加了超出显示范围的处理。比如当 `self.minimum()` 和 `self.maximum()` 值相等时防止除以零错误。
3. 为方便测试,增加一个主窗口类 `MainWindow`, 承载 `NumberLineSlider` 并且显示当前的 Slider 值。

希望对你有帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-21 22:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表