Fletでカウントダウンタイマーを作る
リポジトリ
カウントダウンタイマーを作るにあたって time.sleep()
を使う場合、遅延する恐れがある。
雑に確認したが、20秒で0.2秒ぐらいの誤差になるのは気になるか
import time
diff = 0
for _ in range(20):
start = time.perf_counter()
time.sleep(1.0)
end = time.perf_counter()
print(end - start)
diff += (end - start) - 1.0
print(f"{diff=}")
$ python test.py
1.0135058000014396
1.0103363999951398
1.0089951999980258
1.0015754000050947
1.0078976000077091
1.0112458999938099
1.0125435999943875
1.0147921000025235
1.0131346999987727
1.001626799989026
1.0138484999915818
1.0142044999956852
1.009830899987719
1.0145514000032563
1.0125041999999667
1.0011726999946404
1.015364299993962
1.009197800012771
1.0124055999913253
1.0148489000130212
diff=0.21358229996985756
また、システムが他の処理をスケジュールするために、実行停止時間が要求した時間よりも多少長い時間になることもあります。
https://docs.python.org/ja/3.10/library/time.html?highlight=time perf_counter#time.sleep
公式ドキュメントにもこのように書かれてるので、前のステップとの時間差分で補正するなりしたほうが良さそう。
Fletに良さげなサンプルコードはあったが動かない…
とりあえずこちらをベースに実装してみる。
しかし、threadingライブラリは推奨されていないので後々は書き換えていきたいところ。
時間設定できなかったり、画面サイズなどが適当だったりするが、残り時間をクリックするとタイマー開始・停止するカウントダウンタイマーができた
なるべくウィンドウサイズを小さくしたいので、残り時間表示画面と残り時間設定画面を別画面にしたい。
そのため残り時間表示画面から設定画面に遷移する手段を設ける必要がある。
今のところ考えているのが、以下の通り。
とりあえず上から試してみたい。
- 右下あたりにFloating Action Buttonを追加する。
- https://flet.dev/docs/controls/floatingactionbutton/
- 常に表示されるとなると邪魔なので、ウィンドウにフォーカスされたら表示するとか工夫が必要。
- メニューバーを追加する。
- https://flet.dev/docs/controls/menubar
- ウィンドウサイズが少し大きくなる。
- コンテキストメニューを追加する。
- 現時点では無さそう。
右下あたりにFloating Action Buttonを追加する。
ウィンドウサイズを小さくすると、このように邪魔になる。
Pageのイベントを確認してみる。
on_window_eventが使えそう?
on_window_eventでfocusとblurのイベントを検出できることが確認できた。
FloatingActionButtonについて、公式ドキュメントを確認すると、 visible
プロパティは無さそうにみえるが、ソースコードを確認すると、 visible
プロパティはある。
画面遷移はこれをベースに実装できそう。
TextFieldで数字のみを許可する場合は、 input_filter=ft.NumbersOnlyInputFilter()
を指定する。
最大値、最小値の設定項目はあるのだろう?
max_length
で文字数制限はできるが…
「分に0、秒に150を入力する」みたいなケースもあるので、秒の最大値は設けないでおく。
分と秒のTextFieldに対して、空文字列(数値に変換できない文字列)を受け付けないようにした。
数値に変換できない文字列が入力された場合は、0に置換する。
最前面に固定は page.window_always_on_top
をTrueにすればできる。
差分
そろそろ実行可能ファイルにパッケージ化するため、ワークフローを作成した。
Repository variablesも設定した。
APP_NAME
: countdown-timer
v*
のタグをpushすると自動でパッケージ化を行い、Releaseにアップロードしてくれる。
$ git tag -a v0.0.1 -m 'first release'
$ git push origin v0.0.1
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 161 bytes | 161.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/mh326/countdown-timer.git
* [new tag] v0.0.1 -> v0.0.1
作成されたReleaseはDraft状態なので、手動で公開する。
参考
奮闘記
main.pyが長くなってきたのでViewを別ファイルに分離した。
参考
コマンドライン引数を ArgumentParser (argparse) で取ろうとしたが、 flet run
ではコマンドライン引数を取ることができないっぽい
$ flet run -m 1 -s 30
usage: flet [-h] [--version] {create,run,pack,publish,build} ...
flet: error: unrecognized arguments: -s 30
$ python main.py -m 1 -s 30
Namespace(min='1', sec='30')
flet buildでパッケージ化された実行可能ファイルではコマンドライン引数が無視されている
PS C:\Users\...\countdown-timer\build\windows> .\countdown_timer.exe -m 1 --sec 30
PS C:\Users\...\countdown-timer\build\windows> .\countdown_timer.exe --help
PS C:\Users\...\countdown-timer\build\windows>
flet packでパッケージ化された実行ファイルではコマンドライン引数がちゃんと読み込まれている。
PS C:\Users\...\countdown-timer\dist> .\main.exe -m 1 --sec 30
PS C:\Users\...\countdown-timer\dist> .\main.exe --help
PS C:\Users\...\countdown-timer\dist>
が、 --help
オプションを付けた場合、以下のエラーメッセージが出る。
Traceback (most recent call last):
File "main.py", line 24, in <module>
File "argparse.py", line 1833, in parse_args
File "argparse.py", line 1866, in parse_known_args
File "argparse.py", line 2079, in _parse_known_args
File "argparse.py", line 2019, in consume_optional
File "argparse.py", line 1943, in take_action
File "argparse.py", line 1106, in __call__
File "argparse.py", line 2567, in print_help
File "argparse.py", line 2573, in _print_message
AttributeError: 'NoneType' object has no attribute 'write'
ここら辺も試したがうまくいかなかった。
動作に支障はないのでこのままでいいか。
パッケージ化するワークフローを flet build
から flet pack
に変更し、リリースした。