キュートなタイマー
PyQtの練習でタイマーを作りました。
日本語資料が少ないので大変。
それに、コンソール上Ctrl+Cで死んでくれない、
インタラクティブシェルでQApplicationを作ると入力が重くなって、
実質的にインタラクティブシェルでの実験は無理・・・
wxPythonより高度っぽいですが、ちょっとワガママ?
#encoding:shift-jis from __future__ import division, with_statement, print_function import sys from itertools import * import time import math from PyQt4.QtGui import * from PyQt4.QtCore import * def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = tee(iterable) next(b, None) return izip(a, b) class TimerThread(QThread): def __init__(self, parent, length, interval=0.1): QThread.__init__(self, parent) self.length = length self._stop = False self.interval = interval def stop(self): self._stop = True def run(self): starttime = time.time() while not self._stop: remain = int(math.ceil(self.length - (time.time() - starttime))) self.emit(SIGNAL('tick(int)'), remain) if remain == 0: self.emit(SIGNAL('finish()')) break time.sleep(self.interval) def setTabOrders(*widgets): for w1, w2 in pairwise(widgets): QWidget.setTabOrder(w1, w2) class TimerWindow(QWidget): def __init__(self, parent=None): super(TimerWindow, self).__init__(parent) font = self.font() font.setPointSize(18) self.setFont(font) self.min = QLineEdit(self) self.min.setValidator(QIntValidator(self)) self.sec = QLineEdit(self) self.sec.setValidator(QIntValidator(self)) self.btn = QPushButton("Start", self) self.btn.setDefault(True) toplayout = QHBoxLayout() toplayout.addWidget(self.min) toplayout.addWidget(QLabel(u"分")) toplayout.addWidget(self.sec) toplayout.addWidget(QLabel(u"秒")) bottomlayout = QHBoxLayout() bottomlayout.addWidget(self.btn) layout = QVBoxLayout() layout.addLayout(toplayout) layout.addLayout(bottomlayout) self.setLayout(layout) self.reset_display() setTabOrders(self.min, self.sec, self.btn, self.min) self.min.setFocus() self.min.selectAll() self.resize(300, 100) QObject.connect(self.btn, SIGNAL("clicked()"), self.start) def select_sec(): self.sec.setFocus() self.sec.selectAll() QObject.connect(self.min, SIGNAL("returnPressed()"), select_sec) QObject.connect(self.sec, SIGNAL("returnPressed()"), self.start) def start(self): def err(msg): QMessageBox.warning(self, "Timer", msg) secstr = unicode(self.sec.text()).strip() minstr = unicode(self.min.text()).strip() if not minstr: err(u"分を入力してください") return if not secstr: err(u"秒を入力してください") return try: m = int(minstr) except ValueError as e: err(u"分を半角数字で入力してください") return try: s = int(secstr) except ValueError as e: err(u"秒を半角数字で入力してください") return self.min.setEnabled(False) self.sec.setEnabled(False) self.btn.setText("Stop") QObject.disconnect(self.btn, SIGNAL("clicked()"), self.start) QObject.connect(self.btn, SIGNAL("clicked()"), self.stop) self.timer = TimerThread(self, m * 60 + s) QObject.connect(self.timer, SIGNAL('tick(int)'), self.tick) QObject.connect(self.timer, SIGNAL('finish()'), self.finish) self.timer.start() def stop(self): self.timer.stop() self.sec.setEnabled(True) self.min.setEnabled(True) self.setWindowTitle("Timer") self.min.setFocus() self.min.selectAll() self.btn.setText("Start") QObject.disconnect(self.btn, SIGNAL("clicked()"), self.stop) QObject.connect(self.btn, SIGNAL("clicked()"), self.start) def tick(self, remain): m, s = remain // 60, remain % 60 self.min.setText(unicode(m)) self.sec.setText(unicode(s)) self.setWindowTitle(u"残{0}分{1}秒".format(m, s)) def finish(self): self.stop() self.reset_display() QMessageBox.information(self, "Timer", u"時間です") def reset_display(self): self.min.setText("0") self.sec.setText("0") self.setWindowTitle("Timer") def main(): global app app = QApplication(sys.argv) w = TimerWindow() w.show() app.exec_() if __name__ == "__main__": import doctest doctest.testmod() main()