PyQt5 - 我如何在 QDateEdit 上禁用周末
Posted
技术标签:
【中文标题】PyQt5 - 我如何在 QDateEdit 上禁用周末【英文标题】:PyQt5 - How can I disable weekend on a QDateEdit 【发布时间】:2021-12-19 13:57:31 【问题描述】:我正在使用 QDateEdit 选择特定日期,但我想取消周末,我只想选择工作日。
self.date = QDateEdit(calendarPopup = True)
self.date.setDisplayFormat("dd-MM-yyyy")
self.date.setMinimumDate(QDate(2021,10,1))
self.date.setDate(QDate(datetime.today()))
【问题讨论】:
“禁用”是什么意思? “不可选择”? 没错,我不想选择周末的日子 【参考方案1】:QCalendarWidget 只允许接受单个范围的日期,并且可以选择该范围内的所有日期。
我能想到的唯一解决方案(除了从头开始创建自己的日历)是子类化 QCalendarWidget,访问底层 QTableView(显示日历的内容)并执行以下操作:
设置选择模式为NoSelection
;
在视图(过滤按键)和视图的视口(过滤鼠标事件)上安装事件过滤器;
实现dateForIndex
以检索表格特定索引处显示的日期;
只要鼠标位置的索引为工作日,就将选择模式设置为SingleSelection
,否则将其设置回NoSelection
;
在使用键盘导航时实施适当的选择以避免/跳过周末;
class CalendarWidget(QtWidgets.QCalendarWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setSelectionMode(self.NoSelection)
self.view = self.findChild(QtWidgets.QAbstractItemView, 'qt_calendar_calendarview')
self.view.installEventFilter(self)
self.view.viewport().installEventFilter(self)
def dateForIndex(self, index):
row = index.row()
column = index.column()
if self.horizontalHeaderFormat():
row -= 1
if self.verticalHeaderFormat():
column -= 1
if not 0 <= row <= 5 or not 0 <= column <= 6:
return QtCore.QDate()
day = index.data()
month = self.monthShown()
year = self.yearShown()
# day numbers bigger than 21 cannot be shown in the first 3 rows
if row <= 2 and day > 21:
month -= 1
if month <= 0:
month = 12
year -= 1
# day numbers smaller than 15 cannot be shown in the last 3 rows
elif row >= 3 and day < 15:
month += 1
if month >= 13:
month = 1
year += 1
date = QtCore.QDate(year, month, day)
if self.minimumDate() <= date <= self.maximumDate():
return date
return QtCore.QDate()
def moveCursor(self, key):
currentDate = self.dateForIndex(self.view.currentIndex())
delta = 1
if key == QtCore.Qt.Key_Up:
newDate = currentDate.addDays(-7)
elif key == QtCore.Qt.Key_Down:
newDate = currentDate.addDays(7)
elif key == QtCore.Qt.Key_Left:
newDate = currentDate.addDays(-1)
elif key == QtCore.Qt.Key_Right:
newDate = currentDate.addDays(1)
elif key == QtCore.Qt.Key_Home:
newDate = QtCore.QDate(currentDate.year(), currentDate.month(), 1)
delta = -1
elif key == QtCore.Qt.Key_End:
newDate = QtCore.QDate(currentDate.year(), currentDate.month(),
currentDate.daysInMonth())
delta = -1
elif key == QtCore.Qt.Key_PageUp:
newDate = currentDate.addMonths(-1)
delta = -1
elif key == QtCore.Qt.Key_PageDown:
newDate = currentDate.addMonths(1)
delta = -1
else:
return
newDate = max(self.minimumDate(), min(newDate, self.maximumDate()))
if currentDate != newDate:
# if it's a day of the weekend, add the delta until a work day is
# found; for Home/End/Page keys the delta is inverted, as we need to
# ensure that we stay in the days of the selected month, and if the
# function reaches a weekend it could skip a month
while newDate.dayOfWeek() > 5:
if newDate > currentDate:
newDate = newDate.addDays(delta)
else:
newDate = newDate.addDays(-delta)
if self.minimumDate() <= newDate <= self.maximumDate():
return newDate
def eventFilter(self, obj, event):
if (event.type() in (event.MouseButtonPress, event.MouseButtonRelease, event.MouseButtonDblClick)
and event.button() == QtCore.Qt.LeftButton):
index = self.view.indexAt(event.pos())
if index.isValid():
date = self.dateForIndex(index)
if date.dayOfWeek() <= 5:
self.setSelectionMode(self.SingleSelection)
else:
self.setSelectionMode(self.NoSelection)
elif event.type() == event.MouseMove and event.buttons() == QtCore.Qt.LeftButton:
index = self.view.indexAt(event.pos())
if index.isValid():
date = self.dateForIndex(index)
if not date.isValid() or date.dayOfWeek() > 5:
# ignore mouse move events for weekends
return True
elif event.type() == event.KeyPress:
newDate = self.moveCursor(event.key())
if newDate:
self.setSelectedDate(newDate)
return True
return super().eventFilter(obj, event)
此实现的唯一问题是,如果设置了 dateEditEnabled
(这是默认设置),则无法阻止选择周末日期,除非连接到 activated
和 selectionChanged
信号并最终重置所选日期为有效日期。
【讨论】:
以上是关于PyQt5 - 我如何在 QDateEdit 上禁用周末的主要内容,如果未能解决你的问题,请参考以下文章
Qt/PyQt4/PySide QDateEdit 日历弹窗掉屏