Tkinterでタブを使ったアプリ

# はじめに
Tkinterでタブ付きウィンドウを使った簡単なアプリを作ります。前回の「[TkinterのTextで簡単GUIアプリ](https://qiita.com/TANAKA-V/items/7ad0ccd5d08fc2258d63)」で作った「エデイタ」風アプリにタブ付きウィンドウを導入し複数ファイルの編集を可能にします。タブ付きウィンドウを作るときはtkinter.ttkモジュールのNotebookウィジェットを使います。

# 完成イメージ
タブ付きウィンドウを使った「エディタ」風アプリです。
![tabedit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94910/61f0c8fa-4820-0a68-6b05-5bd0c487c8ee.png)
# 解説
### インポート
tkinterとtkinter.ttkをインポートします。

```Python
import tkinter as tk
import tkinter.ttk as ttk
```
### Notebookの作成
Notebookを作成してアプリのウィンドウに配置します。

```Python
root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.pack(fill='both',expand=1)
```
### タブの追加
タブに配置するフレームを作成し、Notebook.add()でタブを追加します。このままだと追加されたタブが裏に隠れているのでNotebook.select()で前面にします。Notebook.tabs()はtab_idリストを返しNotebook.index('end')がタブ数を返すので、タブ数を-1してリスト最後のtab_idをNotebook.select()に渡します。

```Python
frame=tk.Frame(notebook)
notebook.add(frame,text='title')
notebook.select(notebook.tabs()[notebook.index('end')-1])
```
### 選択されたタブ
引数のないNotebook.select()で選択されたタブのtab_idを返します。Notebook.tabs()が返したtab_idリストのindex()メソッドに選択されたtab_idを引数にして何個目に追加されたタブかを調べることができます。

```Python
idx=notebook.tabs().index(notebook.select())
```
# 全ソースコード

```Python
import os
import tkinter as tk
from tkinter import ttk
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 add_tab(fname):
    global tframes,fnames,notebook
    tframe=SbTextFrame(notebook)
    tframes.append(tframe)
    if os.path.isfile(fname):
        f=open(fname,'r')
        lines=f.readlines()
        f.close()
        for line in lines:
            tframe.text.insert('end',line)
    fnames.append(fname)
    title=os.path.basename(fname)
    notebook.add(tframe,text=title)
    notebook.select(notebook.tabs()[notebook.index('end')-1])

def fileopen():
    fname = filedialog.askopenfilename()
    add_tab(fname)

def filesave():
    global tframes,fnames,notebook
    idx = notebook.tabs().index(notebook.select())
    fname = fnames[idx]
    tframe = tframes[idx]
    f = open(fname,'w')
    f.writelines(tframe.text.get('1.0','end-1c'))
    f.close()

def main():
    global root,notebook,tframes,fnames
    root = tk.Tk()
    root.title('tabbed editor')
    root.geometry('400x300')
    notebook = ttk.Notebook(root)
    notebook.pack(fill='both',expand=1)
    tframes = []
    fnames = []
    add_tab('new')
    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()
```
# おわりに
今回はタブ付きウィンドウを使った「エディタ」風アプリを作りました。「エディタ」に限らず複数のウィンドウを使うときはタブを使うと画面がすっきりしていいですよね。