QDateTimeEdit
默认不允许为空,也就是不能存放空串 。网上搜寻了很久始终没找到答案,自行研究下,发现重写两个方法可以实现可空值的 QDateTimeEdit
:
def validate(self, input: str, pos: int) -> Tuple[QValidator.State, str, int]"""
判断 QDateTimeEdit 的输入是否有效,无效则不会输入到 QDateTimeEdit 中。
返回值 QValidator.State 有三种状态:
QValidator.Acceptable:允许;
QValidator.Intermediate:无法确定(即中间值);
QValidator.Invalid:拒绝。
str: 返回输入框应该显示的文本(非最终文本),默认为 input;
int: 返回输入框光标偏移量,默认为 pos。
"""
def textFromDateTime(self, dateTime: QDateTime) -> str"""每当要显示 dateTime 时会调用此函数,返回最终被显示在输入框中的内容。"""
知道这两个方法的作用后开始一顿骚操作:
class DateTimeEdit(QDateTimeEdit):def __init__(self, parent=None):super().__init__(parent)
self.lineEdit().clear() # 初始化时让输入框为空
def validate(self, input: str, pos: int) -> Tuple[QValidator.State, str, int]:if not input: # 允许接受空串return QValidator.Intermediate, '', 0return super().validate(input, pos)
def textFromDateTime(self, dateTime: QDateTime) -> str:return super().textFromDateTime(dateTime) if self.text() else ''
就这么简单!随后你会惊奇的发现,如果初始化后不设置时间 ( setDate
、setDateTime
… 等方法 ) 的话,点击 步进按钮 或 弹出日历按钮 时,居然没有文本显示了?莫慌,只要再重写 mousePressEvent
方法:
def mousePressEvent(self, evt: QMouseEvent) -> None:super().mousePressEvent(evt)if not self.text():
self.setDateTime(QDateTime.currentDateTime())
即可!如果设置了 setCalendarPopup(True)
,并且要求在弹出日历时先不设置文本,而是等选择了日历的时间后再设置,则需要额外定制。具体我说一下思路,可以根据需求微调。
因为设置 calendarWidget
的时间时 QDateTimeEdit
的文本也会跟着改变,反之也是如此 ( calendarWidget
时间也会随着 QDateTimeEdit
变化 ) 。可以在 mousePressEvent
方法中阻止 calendarWidget
发射信号,为其设置上指定的日期后,再解除阻止。然后在连接了 calendarWidget
的信号方法 ( selectionChanged
、clicked
… 等) 中自行设置 QDateTimeEdit
的显示内容。为保证信号只连接一次 ,可以重写 setCalendarPopup
方法:
def mousePressEvent(self, evt: QMouseEvent) -> None:super().mousePressEvent(evt)if not self.text():# 阻止 calendarWidget 自行改变 QDateTimeEdit 的显示时间(w := self.calendarWidget()).blockSignals(True)
w.setSelectedDate(QDate.currentDate())
w.blockSignals(False)
def setCalendarPopup(self, enable: bool) -> None:super().setCalendarPopup(enable)if enable:# 保证信号只连接一次if not (w := self.calendarWidget()).receivers(w.clicked):
w.clicked.connect(self.setDate)
另附上便捷设置 QDateTimeEdit
时间的方法:
def setDateTime(self, dateTime: Union[QDateTime, str]):
self._set_time(dateTime, QDateTime)
def setDate(self, date: Union[QDate, str]):
self._set_time(date, QDate)
def setTime(self, time: Union[QTime, str]):
self._set_time(time, QTime)
def _set_time(self, t: Union[QDate, QTime, QDateTime], cls):
fmt = self.displayFormat()
t = cls.fromString(t, fmt) if isinstance(t, str) else t
# 这里不用担心给定的字符串会显示出错,# 因为中间还会经过 validate、textFromDateTime 方法,# 验证后返回最终被显示的文本,验证无效则不会显示在输入框中。
self.lineEdit().setText(t.toString(fmt))