鱼C论坛

 找回密码
 立即注册
查看: 127|回复: 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)

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

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

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

    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

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

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

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

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

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

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

        # 布局
        layout = QVBoxLayout()
        layout.addWidget(self.slider)
        layout.addWidget(self.label)
        self.setLayout(layout)

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

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

class NumberLineSlider(QSlider):
    def __init__(self, min_value, max_value, *args, **kwargs):
        super().__init__(Qt.Horizontal, *args, **kwargs)
        self.min_value = min_value
        self.max_value = max_value
        self.setMinimum(min_value)
        self.setMaximum(max_value)
        self.setTickPosition(QSlider.TicksBelow)
        self.setTickInterval(1)  # 设置每个刻度的间隔为1
    
    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        slider_width = self.width()
        slider_height = self.height()
        
        for value in range(self.min_value, self.max_value + 1):
            x = self.position_for_value(value, slider_width)
            painter.drawLine(x, slider_height - 20, x, slider_height - 10)
            
            text = str(value)
            font_metrics = painter.fontMetrics()
            text_width = font_metrics.horizontalAdvance(text)  # 更新点:使用 horizontalAdvance 而不是 width
            painter.drawText(x - text_width // 2, slider_height - 30, text)
    
    def position_for_value(self, value, slider_width):
        """计算给定数值在滑块上的 x 坐标"""
        slider_min = self.minimum()
        slider_max = self.maximum()
        if slider_max == slider_min:
            return 0
        return int(slider_width * (value - slider_min) / (slider_max - slider_min))

# 主窗口
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Number Line Slider Example')
        self.setGeometry(100, 100, 600, 100)
        
        layout = QVBoxLayout()
        
        self.slider = NumberLineSlider(0, 10)
        layout.addWidget(self.slider)
        
        self.value_label = QLabel("0")
        layout.addWidget(self.value_label)
        
        self.slider.valueChanged.connect(self.update_label)
        
        self.setLayout(layout)
        
    def update_label(self, value):
        self.value_label.setText(str(value))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 18:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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