zoukankan      html  css  js  c++  java
  • 手机闹钟功能: 使用状态图解决闹钟响铃问题

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

    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()

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

    以下是状态图:

  • 相关阅读:
    并发编程-阻塞队列&JUC常用工具
    并发编程-Condition源码分析&基于Condition实现阻塞队列
    并发编程-ReentrantLock锁源码分析&Condition设计
    并发编程-JMM&ReentrantLock锁以及原理
    数据库操作支持函数
    python内置进制转换函数
    三目运算符
    数据库常见操作
    宏使用汇总
    sort: invalid comparator
  • 原文地址:https://www.cnblogs.com/diysoul/p/13138772.html
Copyright © 2011-2022 走看看