本文为作者原创,转载请注明出处:https://www.cnblogs.com/apocelipes/p/10533863.html
本文索引
引论 实现CustomDateEdit
过滤用户输入——inputMask 数据验证——QValidator 自动补全——QCompleter CustomDateEdit的实现 测试CustomDateEdit
引论
inputMask
和QValidator
实现,前者负责过滤用户的输入,后者则用于过滤后的信息的验证。inputMask
和validator
的表现很相似,有时它们的功能还会有一些重合,那么它们是否能取代彼此呢?答案是否定的,看起来像鸭子的鸟有时候其实不是和鸭子没关系,后面我们仔细说明。QCompleter
对象传递给QLineEdit。是不是够简单?大部分时间也确实如此,然而“设置好的”这一形容词的很抽象的概念,所以有的时候你可能要失望了,不过别担心,后面我们也会详细介绍它的使用。DateEdit
(我知道有现成的QDateEdit,不过这里请允许我为了实践所学而造一个粗糙的轮子),并根据用户输入的日期计算当天是周几,效果如下:实现CustomDateEdit
inputMask
的功能。过滤用户输入——inputMask
text
槽都只能获取符合mask要求的输入数据,当然这个“用户”包括我们后面要介绍的QValidator
及其派生类。([特殊字符]|[普通字符])*;占位符
,分号后跟的是占位符,用于填充特殊字符留下的空位,默认为空格。下面看些例子:-
000,000.00;_
:用于输入一个最大6位,有两位小数的值,用_
填充空位,edit会显示出类似___,___.__
的效果 -
>AAAA-AAAA!-AAAA-AAAA
:用于输入一个由连字符分割的字母数字组成的uuid或license key,且前八个字母会被转换为大写,在edit中显示为- - -
-
9999年09月09日
:用于输入年月日的时间格式,可以输入2019年03月14日
或2019年3月14日
,显示效果在引论的效果图中。 -
空字符串:表示没有任何输入限制
setInputMask
设置mask,或inputMask
获取当前的mask。-
inputMask在用户进行输入时进行过滤,并且只存在符合规则和不符合两种状态,validator通常拥有第三种状态 -
inputMask只能过滤较为固定的格式,并且对于输入的最大长度产生限制,validator则要灵活的多
数据验证——QValidator
QValidator
了,所有的验证器都是它的派生类。QValidator
本身是一个纯虚基类,派生类需要实现QValidator::State QValidator::validate(QString &input, int &pos) const
进行数据的验证,还有一个可选的fixup
函数用于修复输入,不过一般来说很少有自行修复输入的需求,所以这里使用默认的实现,也就是什么都不做。validate
验证数据后返回数据是否合法,有QValidator::State
类型的值表示:-
QValidator::Invalid
数据不合法 -
QValidator::Intermediate
数据不完整需要进一步的输入 -
QValidator::Acceptable
数据合法
QValidator::State
之外还需要把input
和pos
原封不动地作为第二和第三个值返回,否则edit无法正确显示输入的数据。validator
和setValidator
来获取和设置验证器。CustomDateEdit
(我知道这个工作交给QRegExpValidator会很简单),同时介绍如何实现一个验证器。class CustomDateValidator(QValidator):
"""验证输入的是否是合法的年月日
"""
def validate(self, input: str, pos: int):
date = input.replace(' ', '') # 去除占位符
y, m, d = self.splitDate(date)
if not (y and m and d):
return QValidator.Intermediate, input, pos
try:
arrow.get(date, self.dateFormat()) # 如果解析失败代表日期输入不合法
except Exception:
return QValidator.Invalid, input, pos
return QValidator.Acceptable, input, pos
def dateFormat(self):
"""返回arrow库使用的日期解析格式,具体参见文档,这里与CustomDateEdit的inputMask保持一致
"""
return self.tr('YYYY年M月D日')
def splitDate(self, date: str):
"""分割日期成年,月,日,以便判断数据是否输入完整,
只要有某一部分为空就表明数据未输入结束
"""
y, date = date.split(self.tr('年'))
m, date = date.split(self.tr('月'))
d = date.split(self.tr('日'))[0]
return y, m, d
-
首先去除占位符,如前文所述 -
接着将输入信息按年月日分割,如果有某一部分为空则代表输入不完整 -
对于完整的输入则使用arrow解析成时间对象,失败则表示输入数据错误
QDoubleValidator
和QRegExpValidator
等现有的验证器,或将它们组合使用,这样更简单也更不容易出错。自动补全——QCompleter
QComboBox
自带了QCompleter,它工作得也很好,所以我们往往忽略了它的存在。当然不只是下拉框,在QLineEdit
中我们也可以用它和它的派生类实现补全效果。completer
和setCompleter
获取和设置completer。
# model是一个QStandardItemModel,后面我们也会使用这个model来设置completer
completer = QCompleter()
model.setParent(completer)
completer.setModel(model)
edit.setCompleter(completer)
QLineEdit
的数据处理流程介绍了一遍,有了这些预备知识下面该实现CustomDateEdit
了。CustomDateEdit的实现
class CustomDateEdit(QLineEdit):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setInputMask(self.tr('9999年09月09日')) # 设置日期格式的inputMask
validator = CustomDateValidator()
self.setValidator(validator) # 设置validator
# 设置completer
self._completer = QCompleter()
self.setCompleter(self._completer)
self.completerModel = QStandardItemModel(parent=self._completer)
self._completer.setModel(self.completerModel)
# 预先填充一些待补全内容
self.addDateRecord("2019年03月14日")
self.addDateRecord("2019年03月15日")
def addDateRecord(self, text: str):
"""当有合法的输入被确认时就将其添加至completerModel,以便再次输入时补全
"""
if self.completerModel.findItems(text): # 避免重复添加
return
item = QStandardItem(text)
self.completerModel.appendRow(item)
def weekDayInfo(self, weekDay: int):
"""返回weekDay对应的名称,后面测试中会被使用
"""
week = {
0: self.tr('周一'),
1: self.tr('周二'),
2: self.tr('周三'),
3: self.tr('周四'),
4: self.tr('周五'),
5: self.tr('周六'),
6: self.tr('周日'),
}
return week[weekDay]
addDateRecord
中完成了。测试CustomDateEdit
CustomDateEdit
之后,我们就要动手实现引论一节中的程序了。CustomDateEdit
的信号即可。class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
center = QWidget()
self.dateEdit = CustomDateEdit()
self.info = QLabel(self.tr('所选日期是'))
self.dateEdit.textEdited.connect(lambda: self.info.setText(self.tr('所选日期是')))
# 输入结束后按回车触发该信号,同时只有输入数据通过过滤和验证后这个信号才会被发送
self.dateEdit.returnPressed.connect(self.calcWeekDay)
layout = QVBoxLayout()
layout.addWidget(self.dateEdit)
layout.addWidget(self.info, alignment=Qt.AlignCenter)
center.setLayout(layout)
self.setCentralWidget(center)
def calcWeekDay(self):
# 计算所选日期是周几
t = arrow.get(self.dateEdit.text(), self.dateEdit.validator().dateFormat())
weekDayInfo = self.dateEdit.weekDayInfo(t.weekday())
self.info.setText(self.tr('所选日期是') + weekDayInfo)
# 添加记录
self.dateEdit.addDateRecord(self.dateEdit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.show()
app.exec_()
CustomDateEdit
:self.tr
这个函数,不用担心,这只是为了以后介绍国际化时做的准备,现在忽略它也没问题。原文始发于微信公众号(汇编语言):QLineEdit拾遗:数据的过滤、验证和补全
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论