tkinter触ってみた。

# はじめに
Tkinterを用いてタバタトレーニング用のタイマーを作成しました。
記録を残したいので投稿してみます。(初投稿)
※　完全に個人利用を目的としております。

## どうして作る？
既存のアプリはすでに多く出回っていますが、
- PC画面で大きな文字を表示したい
- 機能を最小限にしたい
- カウントダウン終了時などに、自分の好みの音声ファイルを再生したい

ので、作ってみます。

## 期待する機能
- ボタンを押すとタイマーが始動
- 20秒/10秒のカウントダウンを1セットとし、計8セット繰り返す
- 20秒のカウントダウンの始めと終わりにそれぞれ音声ファイルを再生する

GUIはボタンとテキスト表示だけあればシンプルで見やすいのではと思ったので、それだけに絞りました。

# 開発
## 開発環境
- windows11
- Anaconda Navigator
python 3.9.18
tk 8.6.12
- Visual Studio Code

:::note warn
音声ファイルを再生するために、winsoundライブラリを用いています。
Windows以外のOSでは正しく再生されずにエラーが発生する恐れがあります。
:::

## 参考文献
### タイマー機能
タイマー機能は、以下のサイトのコードを参考にしました。

https://alicia-ing.com/programming/python/change_screen/

### Tkinterの解像度問題
Tkinterで表示されるテキストは解像度が低い。
解像度自体を調整して対処している方のブログがありましたので、それを参考にしました。

https://www.python-beginners.com/entry/20240303/1709409762


## 実際のコード
再生したい音声ファイルを用意して、ファイルパスをコメント部分の変数に入れてもらえれば、再生できると思います。

私は、VOICEVOXで作成した音声ファイルを利用しました。

```python:tabata-timer.py
import tkinter as tk
import winsound
import ctypes

startSound = "" # セット開始時に再生する音声ファイルのパスを指定
finishSound = "" # セット終了時に再生する音声ファイルのパスを指定
allOverSound = "" # 全セット終了時に再生する音声ファイルのパスを指定
ACTIVETIME = 20
RESTTIME = 10
TOTALSTEP = 15

def start_tabata_timer():
    global time_remaining
    global step_remaining

    time_remaining = ACTIVETIME +1
    step_remaining = TOTALSTEP

    start_button.pack_forget()
    numLabel.pack(padx=20, pady=40)
    winsound.PlaySound(startSound, winsound.SND_FILENAME)
    countdown()

def timer_manage():
    global time_remaining
    global step_remaining

    step_remaining-=1

    if (step_remaining > 0) & ((step_remaining % 2) == 1) :
        winsound.PlaySound(startSound, winsound.SND_FILENAME)
        time_remaining = ACTIVETIME + 1
        countdown()
    elif (step_remaining > 0) & ((step_remaining % 2) == 0):
        winsound.PlaySound(finishSound, winsound.SND_FILENAME)
        time_remaining = RESTTIME + 1
        countdown()
    else:
        numLabel.pack_forget()
        start_button.pack(side="bottom")
        winsound.PlaySound(allOverSound, winsound.SND_FILENAME)

def countdown():
    global time_remaining

    time_remaining -= 1

    numLabel.config(text=str(time_remaining))

    if time_remaining > 0:
        root.after(1000, countdown)
    elif (step_remaining != 0):
        timer_manage()

def close_window():
    root.destroy()
    root.quit()

ctypes.windll.shcore.SetProcessDpiAwareness(1)
root = tk.Tk()
root.title("タバタタイマー")
root.state("zoomed")

start_button = tk.Button(
    root,
    text="開始",
    font=("Helvetica",144),
    background="green",
    command=start_tabata_timer
    )
start_button.pack(side="bottom")
numLabel = tk.Label(root, font=("Helvetica",256))

root.protocol("WM_DELETE_WINDOW", close_window)

root.mainloop()
```

### exe化
調べてみると、anacondaで開発したpythonファイルをpyinstallerでexe化すると、ファイルのサイズが大きくなるようでした。
使用していない余分なライブラリもexeに含まれてしまうのが原因みたい。

案の定、11MBぐらいになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562676/a0a4ba9b-8eb1-8d38-6316-63eae951ec8b.png)

#### アプリ実行時にターミナルが起動してしまうとき
--noconsole をつけることで、実行時にターミナルを起動することが防げるようだった。
```
$ pyinstallet tabata-timer.py --onefile --noconsole
```

### 実行してみると
~~exeをクリックすると、ターミナルが起動して、10秒ほどしてからアプリ本体が起動しました。ターミナルを終了してしまうと、アプリ自体も終了してしまいます。~~
exe化のオプションをつけるとターミナルは起動しなくなりましたが、相変わらず起動には時間がかかります。
exeではなくもとのpyファイル自体を実行した方が、起動が速いという結果になりました...

ボタンを押してタイマー自体は始動しました。音声も再生されています。
しかし、カウントダウンの切り替わるタイミングで、数秒テキストが止まってしまったり、音声がすべて再生されなかったりしました。

修正すべきところは多いですね。

### コードに関して
#### 改善すべき点
- 音声が途切れたり、表示される文字が止まってしまうことがある → コード側の処理の問題だと思う。
音声の再生と他の関数の実行タイミングが競合してるっぽい？
- 起動に時間がかかる。
- ~~ターミナルが起動していないと動作しない。~~


#### 自分用だからと妥協したけど...
- Windous以外でも音声ファイルを再生できるようにする
- タイマーに関わる関数をクラス化すべき？
- exeの容量を減らす →　使用ライブラリ変えてみる or そもそもpython以外の他の言語を使う？

### 

# おわりに
自分しか利用しないのだからと妥協した点は多いですが、普通に使用できました。
気が向いたときに修正していきます。