Python初心者がGUIアプリを作る。（ファイル名から単語を消すやつ）

#環境
pythonのバージョン: 3.7.2
PyInstaller:3.4
他に何を書けば良いのかわからない程度に初心者なので誰か教えてください。
あと[Github](https://github.com/ddg171/filenamechanger/tree/f32b84938c0346186c6d11f82c88f27e0199d730)

#動機
 - せっかくプログラミングを勉強しているのでGUIのなにかを作りたい
 - CUIで文字がずらずら出てくるだけだとやる気が続かない。

→GUIのアプリを何でもいいので作ろう。

#とりあえず作る
##面倒くさい作業を探す
Twitterの画像を保存すると、拡張子に"-orig"とか"-large"とかくっついてきて直すのが面倒。
![f5e5cde9827cf93477bbe344179479cf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425022/8055d75a-9e49-73c4-f221-6a6e9b355985.png)

##CUIでパッと作る。
変数名が雑。

```python:filerename_cui.py
import os, shutil,shelve
import namefix as nf

dir_ ="" #変更対象のあるディレクトリ
keyword="_orig" #変更する単語。
folder_set = False #フォルダを変更対象に含めるかどうか。標準では含めない。

#設定ファイルがある場合は設定を読み出し
latest_config= shelve.open("config")
try:
    keyword = latest_config["keyword"]
    dir_ = latest_config["dir_"]
except KeyError:
    pass
if keyword != "" and dir_ != "":
    latest_config.clear()
latest_config.close()

#リネームしたいファイルのあるディレクトリを指定
print("ファイルのあるディレクトリを指定してください")
if dir_ !="":
    print("空欄の場合は\n{}\nが指定されます".format(dir_))
if dir !="":
    dir_ = input()

#ファイル名から削除したい単語を指定
keyword_select = input("ファイル名から消去したい単語を入力してください\n空欄の場合は{}を削除します。\n".format(keyword))
if keyword_select !="":
    keyword = keyword_select

#変更対象にフォルダを含めるか確認
print("変更対象にフォルダを含めますか？(Y/N)")
if input() =="Y":
    folder_set = True
    print("フォルダを変更対象に含めます")
else:
    print("フォルダを変更対象に含ません")
#指定されたディレクトリのファイル一覧を取得
file_list = nf.dir_check(dir_)
if file_list == False:
    print("ディレクトリあるいはファイルが存在しません。")
else:
    #変更対象のファイル一覧を作成
    file_list= nf.file_filter(dir_,  keyword, folder_set,*file_list)
    if len(file_list) >0:
        print("{}個のファイルを変更します。".format(len(file_list)))
        #変更処理を実行
        nf.rename(dir_, keyword,*file_list)
    else:
        print("変更するファイルはありません。")
    #実施後に設定を保存する
    config = shelve.open("config")
    config["keyword"] =keyword
    config["dir_"] = dir_
    config.close()

print("終了")
```
###処理を関数にまとめる
処理を別の関数として分けるとこの後の作業が楽になるらしい。なのでそれっぽくする。
・・・この段階でバッチファイルの使い方を理解してそこで満足してしまう。1回休み。

```python:namefix.py
import os, shutil

def dir_check(dir_input):
    if os.path.exists(dir_input)== True:
        return os.listdir(dir_input)
    else:
        return False

def file_filter(path_, keyword_input, folder,*file_list ):
    filtered_list =[]
    for item in file_list:
        if keyword_input in item:
            if os.path.isdir(path_+"\\"+ item) and folder==False:
                pass
            elif item == keyword_input:
                pass
            else:
                filtered_list.append(item)
    return filtered_list

def rename(dir_ ,keyword,*file_list,):
    for orig_name in file_list:
        new_name = orig_name.replace(keyword,"")
        shutil.move(dir_ + "\\" + orig_name, dir_ + "\\" + new_name)
    return True
```
##GUIに手を出す
**Tkinter**
作る前の準備で飽きるのが嫌なので、一番簡単に使い始めることができそうなライブラリを使う。
参考資料: [M.Hiroi's Home Page](http://www.nct9.ne.jp/m_hiroi/)
###イベント駆動型プログラミングって何だ
>イベント駆動型プログラミング（イベントくどうがたプログラミング）は、起動すると共にイベントを待機し、起こったイベントに従って処理を行うプログラミングパラダイムのこと。フロー駆動型プログラミングと呼ばれる従来のプログラミングパラダイムに対する概念。「イベント駆動」は「イベントドリブン (event-driven)」とも呼ぶ。
出典: https://ja.wikipedia.org/wiki/イベント駆動型プログラミング

その昔
**「中身が分かっていないのに動かそうとするのって気持ち悪くない？」**
と偉い人に言われた事を思い出しつつ見よう見真似で書く。
（Variableクラスのオブジェクトに値を入れる→ボタンが押されると処理開始→処理で使う変数に入れ直して実際の処理？）

```python:fnfgui.py
tkinter.Label(text=form1_text, font=label_font).pack()
dir_entry = tkinter.Entry(root, textvariable=dir_buffer, width=70)
dir_entry.insert(tkinter.END, dir_init)
dir_entry.pack(anchor = 'w',fill="both" )

tkinter.Label(text=form2_text, font=label_font).pack()
word_entry = tkinter.Entry(root, textvariable=keyword_buffer,width=70)
word_entry.insert(tkinter.END,keyword_init) 
word_entry.pack(anchor = 'w', fill="both" )

chk_btn1=tkinter.Checkbutton(root, text= checkbtn_text, variable= folder_conf, font=checkbtn_font)
chk_btn1.pack(anchor = 'w' ) 


def btn1_action(event):
    dir_= dir_buffer.get()
    keyword= keyword_buffer.get()
    folder_set =folder_conf.get()

    file_list = nf.dir_check(dir_)
    if file_list == False:
        tkinter.messagebox.showerror(title="エラー", message="ディレクトリあるいはファイルが存在しません。")
    else:
       #変更対象のファイル一覧を作成
        file_list= nf.file_filter(dir_,  keyword, folder_set,*file_list)
        if len(file_list) >0:
            if tkinter.messagebox.askokcancel(title="確認",message="{}個のファイルを変更します。".format(len(file_list))) == 1:
                #変更処理を実行
                nf.rename(dir_, keyword,*file_list)
            else:
                tkinter.messagebox.showinfo(title="中断",message="処理を中断します。")
        else:
            tkinter.messagebox.showinfo(title="確認",message="変更するファイルはありません。")
    tkinter.messagebox.showinfo(title="終了",message="処理を終了します")

    #実施後に設定を保存する
    config = shelve.open("config")
    config["keyword"] =keyword
    config["dir_"] = dir_
    config.close()

btn1 = tkinter.Button(text="実行", font=btn_font)
btn1.bind("<Button-1>", btn1_action)
btn1.pack(anchor = 'se' )

root.mainloop()
```

###ウィンドウサイズを固定したい

```python:filerename_cui.py
root = tkinter.Tk()
root.title(app_name)
root.geometry(app_size)
root.resizable(0,0) #ウィンドウサイズを固定
```
これで良いらしい。
root.resizable(hoge,pori)の第1引数で横方向、第2引数で縦方向の大きさ変更を許可するか設定できる。
1なら許可、0なら不許可。

##パッケージ化
PyInstallerであまり深く考えずにパッケージ化する。
![3d0951a97f66fd2a88cb6fa748721e8c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425022/cfd30114-fc0a-68db-d34b-29014ebde9ba.png)

##できあがったもの
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425022/db7349e9-8d07-e0ca-581e-749f4adae02d.png)
フォントがダサい。

##追加したい機能
直前の処理をやり直せたらいい
変更対象をリストアップする機能