Tkinterでタブを使ったアプリ


はじめに

Tkinterでタブ付きウィンドウを使った簡単なアプリを作ります。前回の「TkinterのTextで簡単GUIアプリ」で作った「エデイタ」風アプリにタブ付きウィンドウを導入し複数ファイルの編集を可能にします。タブ付きウィンドウを作るときはtkinter.ttkモジュールのNotebookウィジェットを使います。

完成イメージ

タブ付きウィンドウを使った「エディタ」風アプリです。

解説

インポート

tkinterとtkinter.ttkをインポートします。

import tkinter as tk
import tkinter.ttk as ttk

Notebookの作成

Notebookを作成してアプリのウィンドウに配置します。

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()に渡します。

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を引数にして何個目に追加されたタブかを調べることができます。

idx=notebook.tabs().index(notebook.select())

全ソースコード

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()

おわりに

今回はタブ付きウィンドウを使った「エディタ」風アプリを作りました。「エディタ」に限らず複数のウィンドウを使うときはタブを使うと画面がすっきりしていいですよね。