手机闹钟功能: 使用状态图解决闹钟响铃问题

手机闹钟功能:开启一个闹钟后,到时间时自动响铃,并提示“暂停”几分钟或“关闭”闹钟,如果暂停后,过了暂停的时间又自动响铃,直到到了设置的暂停次数才关闭。下面的代码模拟实现了这样一个功能:

 

from PyQt5.QtCore import *
from product.src.util import log


class TimedSchedule(QObject):
    STATE_INIT = 0
    STATE_START = 1
    STATE_TIME_UP = 2
    STATE_PAUSE = 3
    STATE_STOP = 4

    sigTimeUp = pyqtSignal(int)
    sigPaused = pyqtSignal(int)
    sigStopped = pyqtSignal(int)

    def __init__(self, _id: int, datetime: QDateTime, repeat_interval: int, duration: int
                 , pause_count: int, pause_interval, parent=None):
        super().__init__(parent)
        self.id = _id
        self.datetime = datetime
        self.repeat_interval = repeat_interval
        self.duration = duration
        self.pause_count = pause_count
        self.pause_interval = pause_interval
        self._pause_index = 0
        self.state = self.STATE_INIT
        self.start_timer = QTimer()
        self.start_timer.setSingleShot(True)
        self.start_timer.timeout.connect(self._on_schedule_time_up)
        self.pause_timer = QTimer()
        self.pause_timer.setSingleShot(True)
        self.pause_timer.timeout.connect(self._on_schedule_pause_timeout)

    def start(self):
        log.d('id:%s', self.id)
        dt_now = QDateTime.currentDateTime()
        next_clock_time: QDateTime = self.datetime
        while next_clock_time <= dt_now:
            next_clock_time = next_clock_time.addMSecs(self.repeat_interval)
        time_in_ms = dt_now.msecsTo(next_clock_time)
        self.start_timer.start(time_in_ms)
        self._pause_index = 0
        self.state = self.STATE_START

    def pause(self):
        if self.state != self.STATE_TIME_UP:
            log.d('cannot pause')
            return
        log.d('id:%s', self.id)
        if self.pause_count <= 0 or self._pause_index < self.pause_count:
            self._pause_index += 1
            self.sigPaused.emit(self.id)
            self.pause_timer.stop()
            self.start_timer.start(self.pause_interval)
            self.state = self.STATE_PAUSE
        else:
            self.stop()

    def stop(self):
        if self.state != self.STATE_TIME_UP:
            log.d('cannot stop')
            return
        log.d('id:%s', self.id)
        self.pause_timer.stop()
        self.start_timer.stop()
        self.state = self.STATE_STOP
        self.sigStopped.emit(self.id)

    def _on_schedule_time_up(self):
        log.d('id:%s', self.id)
        self.state = self.STATE_TIME_UP
        self.sigTimeUp.emit(self.id)
        self.start_timer.stop()
        self.pause_timer.start(self.duration)

    def _on_schedule_pause_timeout(self):
        log.d('id:%s', self.id)
        self.pause()


if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import *

    def main():
        app = QApplication(sys.argv)

        _id = 1
        datetime = QDateTime.currentDateTime()
        repeat_interval = 10000
        duration = 5000
        pause_count = 3
        pause_interval = 3000
        test_schedule = TimedSchedule(_id, datetime, repeat_interval, duration, pause_count, pause_interval)
        test_schedule.start()

        def on_pause():
            test_schedule.pause()

        def on_stop():
            test_schedule.stop()

        def on_timeout():
            lbl_time.count += 1
            lbl_time.setText('{}'.format(lbl_time.count))
        timer = QTimer()
        timer.timeout.connect(on_timeout)
        timer.setSingleShot(False)
        timer.setInterval(1000)
        timer.start()

        lbl_time = QLabel('0')
        lbl_time.count = 0
        btn_stop = QPushButton('Stop')
        btn_pause = QPushButton('Pause')
        btn_stop.clicked.connect(on_stop)
        btn_pause.clicked.connect(on_pause)
        main_dlg = QDialog()
        main_dlg.setFixedSize(300, 200)
        main_layout = QHBoxLayout(main_dlg)
        main_layout.addWidget(btn_stop)
        main_layout.addWidget(btn_pause)
        main_layout.addWidget(lbl_time)
        main_dlg.show()
        exit_code = app.exec()
        sys.exit(exit_code)

    main()

 

刚开始直接写代码时,比较难理解这个过程,但使用状态图描述后,就变得非常清晰。感觉跟状态机这种高大上的东西还相差很远,暂时先用这个解决问题先,后面学会了再尝试下。

以下是状态图:

 

 

posted @ 2020-06-16 00:40  阿Hai  阅读(567)  评论(0编辑  收藏  举报