ポモタイマー

時間管理術の方法として、ポモドーロテクニックというのがあります。
まぁ、詳しいことは良くわかりませんが、25分集中して作業を行い、5分休憩を取る、というのを繰り返すと、作業効率が上がるらしいです。
人というのは、集中力が持続するのが25分くらいなので、こんなパターンで仕事したり勉強したりするのが、良い結果を生むということみたいです。

好きなことには結構長い時間でも集中できるけれども、仕事となるとねぇ、というグータラな私としては、その辺りの理論はとにかく、その理論に沿ったタイマーを作ってみようかと思った次第でございます。

25分+5分の4サイクル目の休憩は、ちょっと長めが良いということなので、そこのところも考えてみました。
ということで、出来たプログラムはこんな感じです。

# -*- coding: utf-8 -*-

# Created on Tue Nov 30 11:07:23 2021

# 集中力を保った作業を行うために、時間表示を行う
# 25分作業+5分休憩のサイクルが集中力を保つらしい
# 4サイクルごとに15分の休憩を取ると良いみたい
# 強制的に中断する必要は無くて、多少の加減はあっても良い
# という感じのカウントダウンタイマーを作ってみる

# GUIで行うこと
#  カウントダウンタイムを表示(0以下は表示しない)
#  状況に応じて、「作業開始」「休憩開始」ボタンを表示
#  とりあえず、「終了」ボタンも付けてみる
#  サイクル数も表示してみた
# 具体的な作業内容
#  最前面に表示
#  カウントダウンは、真面目にやらなくて、1秒間のsleepを入れる方法にした
#  働くか休むかによって、時間を決める
#  4サイクルに一回の休憩は長めにする

import PySimpleGUI as sg
from time import sleep

# Windows Layout
sg.theme('DarkBlue3')
# 時間表示の横に2行表示するには、columnを使う
layout = [  [sg.T('00:00',key='zan',font=('Helvetica',25),justification='center'),
       sg.Column([[sg.T('待機中',key='inf')],[sg.T(' pomo',key='inf2')]])],
            [sg.Button('作業開始',key='go'),sg.Button('終了',key='end')]  ]

# Make Windows  タイトル無し、ボタンリサイズ無し、最前面表示、どこ掴んでもいい
window = sg.Window('pomo\meter', layout,
    no_titlebar=True,
    auto_size_buttons=False,
    keep_on_top=True,
    grab_anywhere=True) 

# テキストを書き換えるためにオブジェクトを設定する
ResT = window['zan']
Desp = window['inf']
PoT = window['inf2']
BuT = window['go']   

# 作業時間、休憩時間、長めの休憩時間を設定する(秒)
work_time = 1500
rest_time = 300
rest_time_4 = 900

# ポモドーロのサイクル数を記録
pomo_sycle = 0

# 時間と現在の状況とサイクル数とボタンの文字を書き換える関数
def ChangeDesp(secs,ima,tugi):
    Desp.Update(value=ima)
    PoT.update(str(int(pomo_sycle/2+.5))+' pomo')
    BuT.Update(tugi)
    for i in range(secs,-1,-1):
        # 1桁の数字は、0を付けて2桁にする
        dumt = '{:02}'.format(i//60)+':'+'{:02}'.format(i%60)
        print (dumt)
        ResT.Update(value=dumt)
        #表示を書き換える
        window.refresh()
        sleep(1)
    
# Main loop
while True:
    event, values = window.read()
    
    print(event, values) #チェック用
    
    # これがないと無限ループになります
    # プログラムの最後にwindow.close()を書いて終了にする
    if event == sg.WIN_CLOSED: #ウィンドウのXボタンを押したときの処理
        break

    if event == 'end': #終了ボタンを押したときの処理
        break

    # 作業開始か休憩開始を押したときの処理
    if event == 'go':
        pomo_sycle += 1
        if BuT.get_text() == '作業開始':
            ChangeDesp(work_time, '作業中', '休憩開始')
        else :
            # 4サイクルごとに長めの休憩を取る
            if pomo_sycle%8 == 0:
                dt = rest_time_4
            else:
                dt = rest_time
            ChangeDesp(dt, '休憩中', '作業開始')

window.close()

今回のメモ

・時刻表示の右には、現状とサイクル数を表示
時刻表示の横に、今は作業中か休憩中かを表示するのと、その下に何サイクル目かを表示したかったわけです。
図にしてみると、=こんな感じです。
PySympleGUIは、1行づつの積み重ねの感じがあったので、テキストの横に2行のテキストを表示するときは、どうするのかと調べていましたら、Columnってのを使えば良い、ってことが解ったので、使ってみました。

・タイマーだけ表示されれば良い
常に画面に表示していてほしいし、メニューなんかもいらないなぁ、と思って、いろいろ探していたら、Windowを作る時の設定で、「タイトル無し、ボタンリサイズ無し、最前面表示、どこ掴んでもいい」という条件にピッタリのタイマーを作っているプログラムがあったので、ありがたく使わせていただくことにしました。

・Windowの書き換えは、基本自動で行われないっぽい
最初に、約1秒ごとに書き換えるように書いた時は、プログラム的に間違ってるわけじゃないのに、途中では表示が変わらないのに、それぞれの時間が終わると、シレッと表示が変わる、ということが起こりました。
考え方としては、プログレスバーと同じはずなので、書き変わらない理由が分かりませんでした。
困っていたのですが、マニュアルを読んでいたところ、Windowオブジェクトのメソッドにrefreshというのがあることが書いてあったので、使ってみたら、考えていたように表示されました。
ということで、プログレスバーは全体の表示も巻き込んで書き換える機能を持ってるけれども、一般的なオブジェクトはそんなことはしない、と理解することにしました。
これで問題無いうちは、この考え方で対処していくことにします。

・今後の改良
カウントダウン途中でボタン押しても何も起こらないが、そもそも押せませんぜ、ということにしたほうがいいような気もしている。