Pythonで文字数カウンターを作ってみた

# はじめに
皆さんはMicrosoftのWordをお使いになるでしょうか？私も大学のレポートを書く際に、word形式で提出となるとWordを起動させて、レポートを書きます。最近ではGoogle Documentを用いてレポートを書くことも増えましたが...けれど、世の中Wordを開くほどの文章を書くわけでもない...ブラウザ立ち上げてGoogle Documentを開くまでもない...というメモ程度のことを記すだけのこともあるのではないでしょうか？（私だけ？）
そんな時、ああ、文字数カウントしたい...と思うこともしばしばなのではないでしょうか？（わたry）
そんなわけで、Pythonで文字数カウンター作ってみました。忙しい方向けに、ソースコードは[こちら。](#4-ソースコード)

# 環境
Mac OS Catalina
Python 3.7.6
PySimpleGUI 4.18.2

## 0. 目次
1. [ライブラリ](#1-ライブラリ)
2. [必要な機能](#2-必要な機能)
3. [実装](#3-実装)
4. [ソースコード](#4-ソースコード)
5. [まとめ](#5-まとめ)
6. [参考文献](#6-参考文献)

## 1. ライブラリ
PythonでGUIを実装するとなると、真っ先に思いつくのはTkinterかと思います。Tkinterでの実装も考えましたが、なんとなく、やや複雑だな...と思っていたので、他に良いライブラリはないかなと探してみると、ありました、**[PySimpleGUI](https://pysimplegui.readthedocs.io/en/latest/)**が。というわけで、今回はこちらのライブラリを用いて実装を進めていきます。

## 2. 必要な機能
文字数カウンターに個人的に必要な機能としては、

- 文字数を入力するエリア

- カウントボタン

- Quitボタン

くらいがあればなんとかなります。必要最小限の機能で十分です。だってちょっと動かすだけだし。この3つを実装していきます。

## 3. 実装
まず、PySimpleGUIをインストールします。まだインストールしてない場合は、ターミナルで

```
pip install pysimplegui
```
と入力します。

インストールが終わりましたら、早速実装に入ります。

今回importしたのは

- ``` re ```
- ``` PySimpleGUI as sg ```

の2つです。

冒頭でThemeを設定します。見た目が好みなので私は``` DarkAmber ```を選択しました。この辺はお好みで。詳しくは[こちら](https://pysimplegui.readthedocs.io/en/latest/cookbook/#look-and-feel-theme-explosion)から。

```python:wordcounter.py
import PySimpleGUI as sg
import re

sg.theme('DarmAmber')
```
これでThemeの設定は完了です。次にGUIのレイアウト考えます。レイアウトは、

```
layout = []
```
のように、配列の形で自由に設定できます。
私は

```python:wordcounter.py
import PySimpleGUI as sg 
import re

sg.theme('DarkAmber')

layout = [
	[sg.Text('Word Counter')],
	[sg.Multiline((), size=(70, 30))],
	[sg.Submit(button_text='Count', size=(5, 1)), sg.Button('Quit', size=(5, 1))],
	[sg.Button('Delete', size=(5, 1)), sg.Button('Save', size=(5, 1))]
]
```

のようにしました。するとこんな感じになります。

![image1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352625/15fb1110-6a41-2d1b-8839-9f681af330dc.png>
)

かなり直感的に書けるのではないでしょうか。

大雑把に説明しますと、

- ```Text()```では一行でのテキストエリアを表示します
- ```Multiline()```では、複数行のテキストエリアを表示します
- ```Submit()```では、ボタンを表示します
- ```Button()```では、ボタンを表示します

```size=()```では、要素の大きさを指定できます。1=1文字でカウントできるので、私の場合、```Multiline(), size=(70, 30)```ですと、テキストエリアの大きさは、**縦70文字x横30文字**という風に設定しています。

正直、```Submit()```と```Button()```の違いがよくわからないのですが、今回は特に問題なく動作しているのでそのままにしてます...

レイアウトが完成したら、残りはボタンを押した時の動きを設定します。
とその前に、作ったレイアウトを表示するようにします。

```python:wordcounter.py
import PySimpleGUI as sg 
import re

sg.theme('DarkAmber')

layout = [
	[sg.Text('Word Counter')],
	[sg.Multiline((), size=(70, 30))],
	[sg.Submit(button_text='Count', size=(5, 1)), sg.Button('Quit', size=(5, 1))],
	[sg.Button('Delete', size=(5, 1)), sg.Button('Save', size=(5, 1))]
]

window = sg.Window('Word Counter', layout)

#省略

	
window.close()
```

追加したのは

```
window = sg.Window('Word Counter', layout)
```

と

```
window.close()
```

です。残りのプログラムはこの2つの間に書きます。
```while```文で実装していきます。

```python:wordcounter.py
#省略
while True:
	event, values = window.read()

	if event is None:
		print('No words')
		break

	if event == 'Count':
		show_message = len(values[0]) - 1
		print(show_message)

		sg.popup('Result', show_message)

	if event == 'Quit':
		break

	if event == 'Delete':
		sg.PopupYesNo('Are you really?')
		if 'Yes':
			values[0] = re.sub()

```
以下、```if```以下を個別に記述します。

```
if event is None:
		print('No words')
		break
```

xボタンが押された時の動きを記述しています。

```
if event == 'Count':
		show_message = len(values[0]) - 1
		print(show_message)

		sg.popup('Result', show_message)
```

ここがメインになります。変数```show_message```にテキストエリアの値を```len()```で数えた値を代入するようにします。PySimpleGUIでは、テキストボックスやエリアに入れた値は```values[]```で取得出来るようです。他にもやり方はあるようです。
```len(values[0]) - 1```にしている理由は、何度か検証したところ、なぜかテキストに入力した文字数よりも1多い数が出力されるので、-1で帳尻を合わせています。なんでだろ？ともかく、これで動くことには動くので良しとしています。より良い書き方をご存知の方は是非ご教示ください。

```
if event == 'Quit':
		break
```

そのままです。```Quit```を押すとプログラムが終了します。

```
if event == 'Delete':
		sg.PopupYesNo('Are you really?')
		if 'Yes':
			values[0] = re.sub()
```

これはまだ未実装なのですが、```Delete```を押すとテキストエリアにある文字列を全て消すようにしたい...のですが、上手くいきません。正規表現を使って消そうかなとも思うのですが、もっと良いやり方がありそうだな...と思っているのですが、思い付かずここはそのままにしています。まあこの機能はなくても差し支えはないのですが、もっと便利にしたいな...ご存知の方どなたかお力添えください。


以上で私が欲しかった機能を搭載したツールが完成しました。


## 4. ソースコード

以下ソースコードです。

<details><summary>ソースコード</summary>
<div>

```python:wordcounter.py
import PySimpleGUI as sg 
import re

sg.theme('DarkAmber')

layout = [
	[sg.Text('Word Counter')],
	[sg.Multiline((), size=(70, 30))],
	[sg.Submit(button_text='Count', size=(5, 1)), sg.Button('Quit', size=(5, 1))],
	[sg.Button('Delete', size=(5, 1)), sg.Button('Save', size=(5, 1))]
]

window = sg.Window('Word Counter', layout)

while True:
	event, values = window.read()

	if event is None:
		print('No words')
		break

	if event == 'Count':
		show_message = len(values[0]) - 1
		print(show_message)

		sg.popup('Result', show_message)

	if event == 'Quit':
		break

	if event == 'Delete':
		sg.PopupYesNo('Are you really?')
		if 'Yes':
			values[0] = re.sub()

	
window.close()
```

</div>
<details>
こんくらいです。短い。これでも必要最低限の機能は果たせるので個人的にすごく重宝しています。これを僕はMacのAutomatorで呼び出しをある程度自動化し、Alfredでコマンドを打ってすぐに動かせるようにしました。機会があればこれについても記事を書こうと思います。

## 5. まとめ

このような形で文字数カウンターを作成することが出来ました。わざわざコードを書かずとも、似たようなツールは沢山ありますが、自分だけのツールを作ることも一つ楽しみとして持っていても面白いのではないでしょうか？結構愛着湧いて割と使ってます(笑)
セーブ機能や出力なんかには対応しておらず、純粋に文字列をパッとコピペして今何文字かを判定するためだけに使うような代物ではあります。この他に色んな機能を追加するともっと便利にはなるかなと思います。
ここまで読んでいただきありがとうございました。

## 6. 参考文献

[Tkinterを使うのであればPySimpleGUIを使ってみたらという話](https://qiita.com/dario_okazaki/items/656de21cab5c81cabe59)
[PythonのGUIライブラリ「PySimpleGUI」を触ってみた](https://qiita.com/Baltan1990/items/7ffb4ecee6260a0308c8)
[PySimpleGUI](https://pysimplegui.readthedocs.io/en/latest/)
[PySimpleGUI Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/)
[マイブームPySimpleGUIを紹介](https://note.com/hideharu092/n/n9dc1c1075a7b)
[PySimpleGUIの基本的な使用方法](https://qiita.com/KatsunoriNakamura/items/376da645e52f7ef7f9ef)