pyqt5 部件QTableWidget对某些指定单元格输入数字限制
在本次使用表格控件中需要对某些单元格的输入数字进行特定限制,以符合自己的项目需求,现在把这些记录下来:
# QTableWidget对某些指定单元格满足下述条件: # 1、单元格必须为正数 # 2、数字长度不能超过指定长度 # 3、如果是小数需要保留2位小数 详细代码如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QTableWidget, QTableWidgetItem, QPushButton, QLabel, QLineEdit,QFileDialog, QMessageBox, QDialog, QFormLayout, QStyledItemDelegate)
from PyQt5.QtGui import QBrush, QColor, QFont, QIntValidator, QDoubleValidator, QRegExpValidatorfrom PyQt5.QtCore import Qt, QRegExp, QTimer# QTableWidget对某些指定单元格满足下述条件:
# 1、单元格必须为正数
# 2、数字长度不能超过指定长度
# 3、如果是小数需要保留2位小数
class NoNeg_Len_Decimal_LimitDelegate(QStyledItemDelegate):"""自定义代理,仅对指定单元格应用数字限制规则"""def __init__(self, restricted_cells, restricted_cfgs, def_restricted_cfg, parent=None):super().__init__(parent)# 存储需要限制的单元格坐标 (行, 列)self.restricted_cells = set(restricted_cells)# 最大数字长度(包括整数和小数部分,不包括小数点)self.restricted_cfgs = restricted_cfgsself.def_restricted_cfg = def_restricted_cfgdef createEditor(self, parent, option, index):"""为指定单元格创建带验证器的编辑器,其他单元格使用默认编辑器"""# 检查当前单元格是否在限制列表中i = index.row()j = index.column()if (i, j) in self.restricted_cells:editor = QLineEdit(parent)key = f'{i}_{j}'cell_ij_cfg = self.restricted_cfgs.get(key, self.def_restricted_cfg)min_value = cell_ij_cfg['min_value']max_value = cell_ij_cfg['max_value']decimal_digits = cell_ij_cfg['decimal_digits']# 设置验证器if decimal_digits > 0.1:validator = QDoubleValidator(min_value, # 最小值max_value, # 最大值decimal_digits, # 小数位数editor)validator.setNotation(QDoubleValidator.StandardNotation)else:validator = QIntValidator()editor.setValidator(validator)# 限制输入长度(包括小数点)max_length = cell_ij_cfg['max_length']if decimal_digits > 0.1:max_input_length = max_length + 1 # +1 是为了小数点else:max_input_length = max_lengtheditor.setMaxLength(max_input_length)return editor# 非指定单元格使用默认编辑器return super().createEditor(parent, option, index)def setEditorData(self, editor, index):"""为指定单元格设置编辑器数据时进行格式化"""i = index.row()j = index.column()if (i, j) in self.restricted_cells:key = f'{i}_{j}'cell_ij_cfg = self.restricted_cfgs.get(key, self.def_restricted_cfg)min_value = cell_ij_cfg['min_value']decimal_digits = cell_ij_cfg['decimal_digits']# 读取单元格当前值,默认为0value = index.model().data(index, Qt.DisplayRole) or min_value# 确保值为非负数value = max(min_value, float(value))value = round(value, decimal_digits)# 将格式化后的值存入单元格if decimal_digits < 0.1:show_value = int(value)else:show_value = valueif show_value < 1:show_value = ''editor.setText(f"{show_value}")else:super().setEditorData(editor, index)def setModelData(self, editor, model, index):"""提交数据时对指定单元格进行验证和格式化"""i = index.row()j = index.column()if (i, j) in self.restricted_cells:key = f'{i}_{j}'cell_ij_cfg = self.restricted_cfgs.get(key, self.def_restricted_cfg)# 计算最大值min_value = cell_ij_cfg['min_value']key = f'{i}_{j}'cell_ij_cfg = self.restricted_cfgs.get(key, self.def_restricted_cfg)decimal_digits = cell_ij_cfg['decimal_digits']# 获取用户输入的文本text = editor.text().strip()if not text: # 空输入时设置为非负数value = min_valueelse:try:# 转换为浮点数value = float(text)if value < 0:raise ValueError("必须输入非负数")# 检查数字长度是否符合要求# 移除小数点后检查长度digit_len = 0if '.' in text:digit_nums = text.split('.')digit_len = len(digit_nums)if digit_len > decimal_digits:raise ValueError(f"数字长度不能超过{decimal_digits}位")# 保留2位小数value = round(value, decimal_digits)except ValueError as e:# 显示错误提示QMessageBox.warning(editor.parent(), "输入错误", str(e))# 恢复原来的值old_value = index.model().data(index, Qt.DisplayRole) or min_valueold_value = round(old_value, decimal_digits)editor.setText(f"{old_value}")return# 将格式化后的值存入单元格if decimal_digits < 0.1:show_value = int(value)else:show_value = valueif show_value < 1:show_value = ''model.setData(index, f"{show_value}", Qt.EditRole)else:super().setModelData(editor, model, index)def paint(self, painter, option, index):"""重绘时记录当前索引,用于displayText方法"""self.current_index = indexsuper().paint(painter, option, index)#示例
def demo():table = QtWidgets.QTableWidget()restricted_cells = [(3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (11, 1)]restricted_cfgs = {'3_1': {'min_value': 0, 'max_value': 200, 'decimal_digits': 2, 'max_length': 5},'4_1': {'min_value': 0, 'max_value': 200, 'decimal_digits': 2, 'max_length': 5},'5_1': {'min_value': 0, 'max_value': 200, 'decimal_digits': 2, 'max_length': 5},'6_1': {'min_value': 0, 'max_value': 20, 'decimal_digits': 0, 'max_length': 2},'7_1': {'min_value': 202, 'max_value': 212512, 'decimal_digits': 0, 'max_length': 6},'11_1': {'min_value': 0, 'max_value': 20, 'decimal_digits': 0, 'max_length': 2}, }def_restricted_cfg = {'min_value': 0, 'max_value': 300, 'decimal_digits': 2, 'max_length': 5}delegate = NoNeg_Len_Decimal_LimitDelegate(restricted_cells, restricted_cfgs, def_restricted_cfg)table.setItemDelegate(delegate)