TkinterのTextで簡単GUIアプリ

# はじめに
PythonのTkinterを使って「テキストエディタ」風の簡単GUIアプリを作ります。
テキストウィジェット(Text Widget)と縦横スクロールバー(Scrollbar)を組み込んで再利用しやすいようにクラス(Class)にしました。

# 完成イメージ
シンプルな「テキストエディタ」風アプリです。
![editor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94910/dfa00fad-dd83-3258-e955-15436aa1b74a.gif)

# 解説
### インポート
Pythonの標準GUIライブラリのTkinterとファイルダイアログ(filedialog)を使うため最初にインポート(import)します。

```python
import tkinter as tk
from tkinter import filedialog
```
### テキストフレームクラス
スクロールバー付きのテキストフレームクラスを作成します。
クラスはフレーム(Frame)から派生させテキストと縦スクロールバーと横スクロールバーを作りグリッド(grid)を使って母体のフレームに配置します。

```python
class SbTextFrame(tk.Frame):
    def __init__(self,master):
        super().__init__(master)
        text = tk.Text(self,wrap='none',undo=True)
        x_sb = tk.Scrollbar(self,orient='horizontal')
        y_sb = tk.Scrollbar(self,orient='vertical')
        x_sb.config(command=text.xview)
        y_sb.config(command=text.yview)
        text.config(xscrollcommand=x_sb.set,yscrollcommand=y_sb.set)
        text.grid(column=0,row=0,sticky='nsew')
        x_sb.grid(column=0,row=1,sticky='ew')
        y_sb.grid(column=1,row=0,sticky='ns')
        self.columnconfigure(0,weight=1)
        self.rowconfigure(0,weight=1)
        self.text = text
        self.x_sb = x_sb
        self.y_sb = y_sb
```
### アプリケーションウィンドウ
fileopen()とfilesave()は省略してmain()の解説に飛びます。
main()の最初はアプリケーションウィンドウを作ってタイトルとウィンドウのサイズを設定します。

```python
def main():
    root = tk.Tk()
    root.title('editor')
    root.geometry('400x300')
```
### テキストの配置
次にスクロールバー付きテキストフレームを作成してアプリケーションウインドウに全体に配置します。`expand=True`することでウインドウサイズに合わせてテキストフレームのサイズも変わるようになります。

```python
    textframe = SbTextFrame(root)
    textframe.pack(side='top',fill='both',expand=True)
```
### メニュー作成
ファイルメニューを作成してアプリケーションウインドウのメニューバーに配置します。

```python
    menubar = tk.Menu(root)
    filemenu = tk.Menu(menubar,tearoff=0)
    filemenu.add_command(label='Open',command=fileopen)
    filemenu.add_command(label='Save',command=filesave)
    filemenu.add_command(label='Exit',command=exit)
    menubar.add_cascade(label='File',menu=filemenu)
    root.config(menu=menubar)
```
# 全体のソースコード
全体のソースコードは下記のようになります。

```python
import tkinter as tk
from tkinter import filedialog

class SbTextFrame(tk.Frame):
    def __init__(self,master):
        super().__init__(master)
        text = tk.Text(self,wrap='none',undo=True)
        x_sb = tk.Scrollbar(self,orient='horizontal')
        y_sb = tk.Scrollbar(self,orient='vertical')
        x_sb.config(command=text.xview)
        y_sb.config(command=text.yview)
        text.config(xscrollcommand=x_sb.set,yscrollcommand=y_sb.set)
        text.grid(column=0,row=0,sticky='nsew')
        x_sb.grid(column=0,row=1,sticky='ew')
        y_sb.grid(column=1,row=0,sticky='ns')
        self.columnconfigure(0,weight=1)
        self.rowconfigure(0,weight=1)
        self.text = text
        self.x_sb = x_sb
        self.y_sb = y_sb

def fileopen():
    global fname,textframe,root
    fname = filedialog.askopenfilename()
    f = open(fname,'r')
    lines = f.readlines()
    f.close()
    textframe.text.delete('1.0','end')
    for line in lines:
        textframe.text.insert('end',line)
    root.title('editor - '+fname)

def filesave():
    global fname,textframe
    if fname == '':
        return
    f = open(fname,'w')
    lines = textframe.text.get('1.0','end-1c')
    f.writelines(lines)
    f.close()

def main():
    global fname,textframe,root
    fname = ''
    root = tk.Tk()
    root.title('editor')
    root.geometry('400x300')
    textframe = SbTextFrame(root)
    textframe.pack(side='top',fill='both',expand=True)
    menubar = tk.Menu(root)
    filemenu = tk.Menu(menubar,tearoff=0)
    filemenu.add_command(label='Open',command=fileopen)
    filemenu.add_command(label='Save',command=filesave)
    filemenu.add_command(label='Exit',command=exit)
    menubar.add_cascade(label='File',menu=filemenu)
    root.config(menu=menubar)
    root.mainloop()

if __name__ == '__main__':
    main()
```

# おわりに
今回はPythonで簡単なGUIアプリを作りました。テキストウィジェットに縦横スクロールバーを付けるのが少し面倒だったので、今後は再利用できるようにクラスにしてみました。縦横スクロールバー付きのテキストウィジェットを多用するアプリを作るときは便利だと思います。