PyQt5 - QDateTimeEdit 旋转框翻转

PyQt5 - QDateTimeEdit spinbox rollover

我正在开发一个应用程序以从特定 FTP 平台下载日志文件,我还希望用户能够 select 开始和停止日期单独的 QDateTimeEdit 小部件。这将使程序选择合适的日志文件。

当用户连接到平台时,根据日志文件的可用性设置最小和最大 datetimes,这工作正常,直到用户尝试使用旋转框更进一步例如,从 3 月 31 日到 4 月 1 日的按钮。小部件不会滚动到下个月。

我是否缺少启用或禁用翻转的属性?

我是否可以插入自定义 python (3.6) 代码来创建翻转?我的谷歌搜索除了 custom C++ code from 2008stepBy 什么都没有得到,我读得不太好。

这是 .ui 文件的 XML 版本:

   <widget class="QDateTimeEdit" name="timestart">
    <property name="geometry">
     <rect>
      <x>510</x>
      <y>155</y>
      <width>126</width>
      <height>22</height>
     </rect>
    </property>
    <property name="alignment">
     <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
    </property>
    <property name="displayFormat">
     <string notr="true">yyyy-MM-dd HH:mm:ss</string>
    </property>
   </widget>
   <widget class="QDateTimeEdit" name="timeend">
    <property name="geometry">
     <rect>
      <x>510</x>
      <y>205</y>
      <width>126</width>
      <height>22</height>
     </rect>
    </property>
    <property name="alignment">
     <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
    </property>
    <property name="displayFormat">
     <string notr="true">yyyy-MM-dd HH:mm:ss</string>
    </property>
   </widget>

我意识到启用 calendarPopup 也是一种解决方法,但在设计方面,如果我能找到解决翻转问题的 pythonic 方法,我宁愿不这样做。

一个可能的解决方法是子class QDateTimeEdit 并覆盖两者stepEnabled (which is responsible of showing enabled up/down arrows and allowing actual up/down step action) and then stepBy 以允许更改超出当前day/month/year.

限制的日期

不幸的是,这无法解决在 select 相应月份之前无法输入“无效”日期数字的问题(例如:您不能在 2 月输入 31),但可以实现由于旋转框、游标和完成器之间的相互作用,这样的结果确实复杂。

在下面的代码中,我实现了它,以便所有有效的 date/time 字段实际上都可以向上和向下:月、日、小时、分钟和秒。

class DateTimeFix(QtWidgets.QDateTimeEdit):
    _overrideSteps = (
        QtWidgets.QDateTimeEdit.MonthSection, 
        QtWidgets.QDateTimeEdit.DaySection, 
        QtWidgets.QDateTimeEdit.HourSection, 
        QtWidgets.QDateTimeEdit.MinuteSection, 
        QtWidgets.QDateTimeEdit.SecondSection, 
    )
    def stepEnabled(self):
        if self.currentSection() in self._overrideSteps:
            return self.StepUpEnabled | self.StepDownEnabled
        return super().stepEnabled()

    def stepBy(self, steps):
        section = self.currentSection()
        if section not in self._overrideSteps:
            super().stepBy(steps)
            return
        dt = self.dateTime()
        section = self.currentSection()
        if section == self.MonthSection:
            dt = dt.addMonths(steps)
        elif section == self.DaySection:
            dt = dt.addDays(steps)
        elif section == self.HourSection:
            dt = dt.addSecs(3600 * steps)
        elif section == self.MinuteSection:
            dt = dt.addSecs(60 * steps)
        else:
            dt = dt.addSecs(steps)
        self.setDateTime(dt)

由于您是在 Designer 中创建 UI,因此您需要在 Designer 中提升 QDateTimeEdit 才能使用上述 class。
简化的过程是:右键单击设计器中的 QDateTimeEdit 小部件,然后 select Promote to...,从对话框类型“DateTimeFix”(class 名称)在“Promoted class name" 字段,然后键入要在其中放置上述 class 的文件的名称( 不带 .py 扩展名,就像您使用导入),确保基础 class 名称仍然正确(QDateTimeEdit),单击“添加”,然后单击“提升”。在此过程之后,您可以升级您可能在 ui 中拥有的所有其他 QDateTimeEdit(只需右键单击它们并从新的“升级到”子菜单中 select 它)。有关更详细的说明,请参阅 this answer

我使用了上面@musicamante 所示的代码片段,并进行了一些调整,可能是因为我使用的是 PyQt6。 (基本上,将那些 .Section.StepEnabledFlag 添加到枚举属性)

from PyQt6.QtWidgets import QDateTimeEdit

class DateTimeFix(QDateTimeEdit):
    _overrideSteps = (
        QDateTimeEdit.Section.MonthSection, 
        QDateTimeEdit.Section.DaySection, 
        QDateTimeEdit.Section.HourSection, 
        QDateTimeEdit.Section.MinuteSection, 
        QDateTimeEdit.Section.SecondSection, 
    )
    def stepEnabled(self):
        if self.currentSection() in self._overrideSteps:
            return self.StepEnabledFlag.StepUpEnabled | self.StepEnabledFlag.StepDownEnabled
        return super().stepEnabled()

    def stepBy(self, steps):
        section = self.currentSection()
        if section not in self._overrideSteps:
            super().stepBy(steps)
            return
        dt = self.dateTime()
        section = self.currentSection()
        if section == self.Section.MonthSection:
            dt = dt.addMonths(steps)
        elif section == self.Section.DaySection:
            dt = dt.addDays(steps)
        elif section == self.Section.HourSection:
            dt = dt.addSecs(3600 * steps)
        elif section == self.Section.MinuteSection:
            dt = dt.addSecs(60 * steps)
        else:
            dt = dt.addSecs(steps)
        self.setDateTime(dt)