You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QDoubleSpinBox替换QLineEdit后,如何实现自动添加欧元金额小数分隔符?

欧元格式QDoubleSpinBox实现优化

已实现功能

  • 金额后显示€符号,且该符号不包含在cleanText()返回值中
  • 控件聚焦时€自动隐藏,失焦时重新显示
  • 聚焦时自动全选输入内容

需新增功能

  • 采用逗号作为小数分隔符(符合欧元区金额格式)
  • 实时输入格式化:
    • 输入“0050”时实时显示“00,50”,回车后自动修正为“0,50”
    • 输入“-1050”自动转换为“-10,50”
    • 输入“99”回车后补全为“99,00”
  • 输入超出设置范围时不阻止输入,自动添加逗号切换至小数位输入

修改后的完整代码

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QDoubleSpinBox, QLineEdit, QPushButton
from PyQt5.QtCore import QTimer, QLocale, Qt
from PyQt5.QtGui import QValidator

class EuroDoubleSpinBox(QDoubleSpinBox):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setButtonSymbols(QDoubleSpinBox.NoButtons)
        self.normalSuffix = ''
        self.currencySuffix = ' €'
        self.setSuffix(self.currencySuffix)
        
        # 设置欧元区区域格式,确保逗号作为小数分隔符
        locale = QLocale(QLocale.German, QLocale.Germany)
        self.setLocale(locale)
        self.setDecimals(2)
        self.setRange(-99.99, 99.99)
        self.setSingleStep(0.01)

    def focusInEvent(self, event):
        self.setSuffix(self.normalSuffix)
        QTimer.singleShot(0, self.selectAll)
        super().focusInEvent(event)

    def focusOutEvent(self, event):
        self.setSuffix(self.currencySuffix)
        # 失焦时自动修正最终格式
        self.fixup(self.text())
        super().focusOutEvent(event)

    def validate(self, input_str, pos):
        # 移除后缀与空格
        input_str = input_str.replace(self.currencySuffix, '').strip()
        if not input_str:
            return (QValidator.Acceptable, input_str, pos)
        
        # 处理负号标记
        is_negative = input_str.startswith('-')
        num_part = input_str[1:] if is_negative else input_str
        
        # 过滤非数字字符
        num_part = ''.join([c for c in num_part if c.isdigit()])
        
        # 自动插入逗号分隔整数与小数位
        if len(num_part) <= 2:
            formatted = num_part
        else:
            integer_part = num_part[:-2]
            decimal_part = num_part[-2:]
            formatted = f"{integer_part},{decimal_part}"
        
        # 重新拼接负号
        if is_negative:
            formatted = '-' + formatted
        
        # 调整光标位置,适配插入的逗号
        new_pos = pos
        if ',' in formatted and pos > formatted.index(','):
            new_pos += 1
        
        return (QValidator.Acceptable, formatted, new_pos)

    def fixup(self, input_str):
        # 最终格式修正:补全小数位、去除前导零、修正到范围值
        input_str = input_str.replace(self.currencySuffix, '').strip()
        if not input_str:
            self.setValue(0.00)
            return
        
        try:
            # 转换为浮点数并修正范围
            value = float(input_str.replace(',', '.'))
            value = max(self.minimum(), min(self.maximum(), value))
            # 保留两位小数并设置值
            self.setValue(round(value, 2))
        except ValueError:
            self.setValue(0.00)

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

    def initUI(self):
        layout = QVBoxLayout()
        self.pushbutton = QPushButton('打印SpinBox数值')
        self.lineedit = QLineEdit()  # 用于切换焦点测试
        self.doubleSpinBox = EuroDoubleSpinBox()
        layout.addWidget(self.lineedit)
        layout.addWidget(self.doubleSpinBox)
        layout.addWidget(self.pushbutton)
        self.setLayout(layout)

        self.pushbutton.clicked.connect(lambda: print(self.doubleSpinBox.cleanText()))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setGeometry(100, 100, 200, 100)
    window.setWindowTitle('欧元格式SpinBox')
    window.show()
    sys.exit(app.exec_())

关键实现说明

  1. 实时输入验证:重写validate()方法,实时过滤输入、插入逗号分隔符,同时调整光标位置保证输入流畅度。
  2. 最终格式修正:通过fixup()方法在回车或失焦时,将输入转换为合法浮点数,补全两位小数并修正到设置的数值范围内。
  3. 区域格式适配:设置德语区域确保系统级小数分隔符为逗号,与自定义验证逻辑配合实现标准欧元格式。
  4. 焦点事件增强:保留原有后缀显示逻辑的同时,在失焦时触发最终格式修正,保证显示一致性。

内容的提问来源于stack exchange,提问作者Andreas M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:47:03