手机闹钟功能: 使用状态图解决闹钟响铃问题
手机闹钟功能:开启一个闹钟后,到时间时自动响铃,并提示“暂停”几分钟或“关闭”闹钟,如果暂停后,过了暂停的时间又自动响铃,直到到了设置的暂停次数才关闭。下面的代码模拟实现了这样一个功能:
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()
刚开始直接写代码时,比较难理解这个过程,但使用状态图描述后,就变得非常清晰。感觉跟状态机这种高大上的东西还相差很远,暂时先用这个解决问题先,后面学会了再尝试下。
以下是状态图:
代码养活自己