如何在 QDateTimeEdit 显示格式中使用一年中的某一天?我知道我可以使用 displayFormat 方法指定显示格式,但是 documentation 没有显示使用年中日期格式的方法。前任。 2023 年 7 月 29 日将是 2023-210。
我使用的所有数据都使用序号日期来跟踪信息。因此,最简单的方法是输入序数日期,而不是转换它然后输入它。
我当前的解决方案使用带有输入掩码和验证器方法的行编辑,但我想知道是否有更强大的解决方案。
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class DateEdit(QLineEdit):
def __init__(self):
super().__init__()
self.textChanged.connect(self.validate)
self.setPlaceholderText('yyyy-ddd')
def validate(self):
print(self.cursorPosition())
text = self.text()
print(text.split('-'))
if len(text) > 5 and int(text.split('-')[1]) > 366:
self.setText(text[:-1])
def focusInEvent(self, event):
if self.text() == '':
self.setInputMask('9999-900')
def focusOutEvent(self, event):
if self.text() == '-':
self.setInputMask('')
if __name__ == "__main__":
app = QApplication(sys.argv)
main = QWidget()
main.setFixedSize(200, 100)
edit1 = DateEdit()
edit2 = DateEdit()
layout = QHBoxLayout()
layout.addWidget(edit1)
layout.addWidget(edit2)
main.setLayout(layout)
main.show()
app.exec()
我修改了当前的 QDateEdit 以具有不同的显示和输入文本行为,同时仍然保留 QDateEdit 的功能(例如弹出菜单和上下文菜单)。当前的日期格式现在采用序数日期的形式(例如
2020/123
)。
为了实现这一点,我查看了Qt源代码和Qt文档,经过一番尝试和错误,我发现需要重新实现以下功能:
dateTimeFromText(text)
[1]:用于解析序数日期格式的输入。textFromDateTime(dt)
[2]:用于以正确的格式显示序数日期。validate(text, pos)
[3]:根据序数日期格式更改验证。stepBy(steps)
[4] 和 stepEnabled()
[5]:这两个函数也被重新实现,以修复使用箭头键修改日期时的限制。代码在我的测试中似乎工作正常,但可能存在一些错误。我也没有测试它的区域设置更改,但它应该提供一个很好的起点。 另外,我并不是真正的 Python 程序员,因此代码可能不符合最佳实践。
import sys
from PyQt5.QtGui import QValidator
from PyQt5.QtCore import QDate, QDateTime
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QDateEdit
class CustomDateEdit(QDateEdit):
def __init__(self):
super().__init__()
self.setDisplayFormat('yyyy/dd')
def dateTimeFromText(self, text):
try:
year_str, day_str = text.split('/')
year, day = int(year_str), int(day_str)
except:
year, day = 1, 1
date = QDateTime(QDate(year, 1, 1).addDays(day - 1))
date.setTime(self.time())
return QDateTime(date)
def textFromDateTime(self, dt):
year = dt.date().year()
day = dt.date().dayOfYear()
res = "{0}/{1:0>2}".format(year, day)
return res
def stepBy(self, steps):
if self.currentSection() == QDateEdit.Section.DaySection:
date = self.date()
leap = QDate().isLeapYear(date.year())
if date.dayOfYear() + steps <= (364 + int(leap)):
self.setDate(date.addDays(steps))
else:
super().stepBy(steps)
def stepEnabled(self):
if self.currentSection() == QDateEdit.Section.DaySection:
date = self.date()
leap = QDate().isLeapYear(date.year())
flag = QDateEdit.StepEnabledFlag.StepNone
if date.dayOfYear() < (364 + int(leap)):
flag = QDateEdit.StepEnabledFlag.StepUpEnabled
if 1 < date.dayOfYear():
flag |= QDateEdit.StepEnabledFlag.StepDownEnabled
return flag
else:
return super().stepEnabled()
def validate(self, text, pos):
try:
year_str, day_str = text.split('/')
year, day = int(year_str), int(day_str)
except:
year, day = 1, 1
new_date = QDate(year, 1, 1).addDays(day - 1)
is_leap = new_date.isLeapYear(year)
have_slash = text.count('/') == 1
day_in_range = day < (364 + int(is_leap))
range_valid = self.minimumDate() < new_date and new_date < self.maximumDate()
if have_slash and day_in_range and range_valid:
state = QValidator.Acceptable
elif have_slash and year_str and len(year_str) < 4:
state = QValidator.Intermediate
else:
state = QValidator.Invalid
return (state, text, pos)
if __name__ == "__main__":
app = QApplication(sys.argv)
main = QWidget()
cdate_edit = CustomDateEdit()
cdate_edit.setCalendarPopup(True)
layout = QVBoxLayout()
layout.addWidget(cdate_edit)
main.setLayout(layout)
main.show()
sys.exit(app.exec())