今回は、Pythonの標準ライブラリであるTkinterを用いたGUIのカスタマイズ方法について解説していきます(全2回)。全てを網羅的に解説することは難しいので、よく使われるGUIのウイジット(部品)を中心に、簡単なコード例と併せて補足説明をしていきます。
※) 当ブログの連載が書籍になりました!!(Amazon購入ページ)(書籍の紹介記事)
通常、ウインドウサイズは、ウインドウ右下をマウスでクリックした状態で拡大縮小させることが可能です。resizableメソッドでwidth, heightともに Falseにすることで拡大縮小を防止します。
「filemenu.add_separator()」は、セパレーターです。通常、メニュー間の境界をわかりやすくするために用います。
メニューバーの内容を選択した際の動作は、add_command()の引数「command =」で指定します。ここでは、Fileメニューの「Exit」を選択した際に、ウインドウを「destroy()」で終了させるように指示しています。
ここで「lambda:」とは、ラムダ式といいます。今回のように、わざわざ関数を定義するほどでもない、短いコードを扱うときなどに便利です。また、名前付けされずに定義された関数のことを、「無名関数」と呼びます(ここでは「root.destroy()」)。
スポンサードリンク
read()の引数で、読み込む設定ファイルのファイルパスを指定します。関数「get_path」内で「global file_path」としているのは、「file_path」をグローバル変数として扱うためです。通常、関数の中で宣言した変数は、その関数内でしか参照できません。しかし、変数「file_path」は、他の関数「path_save」でも使用するので、グローバル変数として宣言する必要があります。「filedialog」の使い方は、以前説明したので省略します。
関数「path_save」の「config["Path"] = {"Text" : file_path}」で、ファイルパスをiniファイルへどのように書き込むか指定しています。コードを実行した後、「config.ini」をテキストエディッタで開くと、以下のように、内容が保存されています。ここでは、ファイルパス「D:/test.txt」が保存されています。設定を書き込む際のコードは既出なので、説明を省略します。
「config.ini」に保存された値を、呼び出すには、以下のコードを実行します。ここでは、[Path]セクションの「Text」キーの値を取得しています。つまり、ここでは「D:/test.txt」という値が得られるはずです。
ウイジットの値はget()で取得できます。ここでは、便宜上、変数「value」に全てのウイジットの値を入れています。ですので、エントリーボックスには、値に{}が表示されます(値がタプル型で代入されているため)。{}を表示させたくない場合は、変数に複数の値を入れなければOKです。
# スピンボックス
set()で初期値(アプリケーション起動時の値)を指定します。textvariableは、スピンボックスの値を受け取る変数を指定します。「from_」と「to」で下限と上限値を指定します。
# チェックボタン
set()で初期値(アプリケーション起動時の値)を指定します。variableは、チェックボタンの値を受け取る変数を指定します。「text」は、ボタン横の表示テキスト、「onvalue」と「offvalue」でON/OF時の値を指定します。
# ラジオボタン
variableは、ラジオボタンの値を受け取る変数を指定します。「text」は、ボタン横の表示テキスト、「value」はONの時の値を指定します。
# コンボボックス
変数「combo_dict」に、コンボボックスの内容を辞書型(ディクショナリ)で代入しています。辞書に文字列(key)と数字(value)がセットになった要素を「:」で区分けしています。要素間は「,」のカンマ区切りで分割しています。variableは、コンボボックスに表示する値のリストを指定します。
通常、コンボボックスは、ユーザーが値を入力することも可能です。しかし、ここでは「state = "readonly"」とすることで、ユーザーへの値の書込みを禁止しています。
次回につづきます!!
【関連記事】
Pythonではじめるアプリ開発 ①:Python環境構築編
Pythonではじめるアプリ開発 ②:Python GUI編 その1
Pythonではじめるアプリ開発 ③:Python GUI編 その2
Pythonではじめるアプリ開発 ④:関数編
Pythonではじめるアプリ開発 ⑤:テキスト処理編
Pythonではじめるアプリ開発 ⑥:完成編
Pythonではじめるアプリ開発 ⑦:デバッグ編
Pythonではじめるアプリ開発 ⑧:exe化編
Pythonではじめるアプリ開発 ⑩:改造編 その2(終)
※) 当ブログの連載が書籍になりました!!(Amazon購入ページ)(書籍の紹介記事)
Tkinterの基本ウインドウ
まずは、Tkinterの基本となるウインドウの作成方法です。本連載のはじめに、解説しましたね。今回はこの基本ウインドを元に、色々とカスタマイズしていきます。# tkinterのインポート import tkinter as tk # ウインドウの作成 root = tk.Tk() # ウインドウのサイズ指定 root.geometry("300x100") # ウインドウ状態の維持 root.mainloop()
Tkinterのウインドウオプション
先程の、基本ウインドウの、タイトルバーに「ウインドウの名称(アプリケーション名)」、「アイコン」、そいてウインドウサイズの「固定」といった3つの要素を追加しています。import tkinter as tk root = tk.Tk() root.geometry("300x100") # ウインドウ名 root.title("TestApp") # アイコン root.iconphoto(True, tk.PhotoImage(file = "Images/icon.png")) # ウインドウサイズの固定 root.resizable(width = False, height = False) root.mainloop()アイコンはタイトルバーに表示されるのみです。サイズが大きすぎると、起動が遅くなる場合があるので、注意しましょう。ここでは「16×16px」のPNG画像を使用しています。Macは非対応です。
通常、ウインドウサイズは、ウインドウ右下をマウスでクリックした状態で拡大縮小させることが可能です。resizableメソッドでwidth, heightともに Falseにすることで拡大縮小を防止します。
Tkinterのメニューバー
Tkinterでメニューバーを追加するには、以下のようなコードを使用します。サンプルコードは、ファイルメニューのみですが、画像のように、「File」と同様に「Help」など要素を次々と追加できます。import tkinter as tk root = tk.Tk() root.geometry("300x100") # メニューバーの作成 menubar = tk.Menu(root) root.configure(menu = menubar) # ファイルメニュー filemenu = tk.Menu(menubar, tearoff = 0) menubar.add_cascade(label = "File", menu = filemenu) # ~内容 filemenu.add_command(label = "Open File...")通常、Tkinterではメニューに切り取り線が表示されて、切り取り可能なメニューが表示されます。ここでは、「tearoff = 0」オプションを使用し、メニューの切り取りを防止しています。
# セパレーター filemenu.add_separator() filemenu.add_command(label = "Exit", command = lambda: root.destroy()) root.mainloop()
「filemenu.add_separator()」は、セパレーターです。通常、メニュー間の境界をわかりやすくするために用います。
メニューバーの内容を選択した際の動作は、add_command()の引数「command =」で指定します。ここでは、Fileメニューの「Exit」を選択した際に、ウインドウを「destroy()」で終了させるように指示しています。
ここで「lambda:」とは、ラムダ式といいます。今回のように、わざわざ関数を定義するほどでもない、短いコードを扱うときなどに便利です。また、名前付けされずに定義された関数のことを、「無名関数」と呼びます(ここでは「root.destroy()」)。
スポンサードリンク
Tkinterの新規ウインドウ
基本ウインドウ(親ウインドウ, メインウインドウ)とは別に、サブウインドウ(子ウインドウ)を作りたい場合は、以下のようなコードを使用します。ここでは、[Push]ボタンをクリックした際に、サブウインドウが開くようにしています。親ウインドウを閉じると、サブウインドウも閉じますが、サブウインドウを閉じても親ウインドウは閉じません。import tkinter as tk ##### 関数 ##### def sub_window(): # サブウインドウの作成 about_window = tk.Toplevel(root) about_window.geometry("200x100") ##### GUI ##### root = tk.Tk() root.geometry("300x100") # ボタン push_button = tk.Button(root, text = "Push", command = sub_window) push_button.place(x = 30, y = 30) root.mainloop()方法は簡単です。Toplevel()の引数で、親ウインドウを指定するだけです。親ウインドウと同じように、関数やウイジットを追加するには、関数「sub_window」と同じコードブロックに追加していきます。
Tkinterのメッセージボックス
サブウインドウとは別に、ユーザーに確認や注意をうながす場合は、メッセージボックスを利用します。ここでは、[Push]ボタンをクリックした際に、アプリケーションを終了するか確認のためのメッセージが表示されます。import tkinter as tk import tkinter.messagebox ##### 関数 ##### # 終了確認 def quit_yn(): if tk.messagebox.askyesno("確認", "終了しますか?"): root.destroy() ##### GUI ##### root = tk.Tk() root.geometry("300x100") # ボタン push_button = tk.Button(root, text = "Push", command = quit_yn) push_button.place(x = 30, y = 30) root.mainloop()メッセージボックスは、Tkinterから「messagebox」をインポートすることで使用可能になります。先程の、サブウインドウとは役割が異なるので、上手に使い分けましょう。
Tkinterで設定の保存
Tkinterを使用して、入力した値や、環境設定などの記録を残しておきたい場合は、以下のコード使用します。サンプルコードは、別途「config.ini」とい設定ファイルをPythonファイルと同じディレクトリに置いて実行しています。ここでは、[Push]ボタンをクリックした際に、ファイル選択画面が開き、選択したテキストファイルのファイルパス名を「config.ini」へ保存します。import tkinter as tk from tkinter import filedialog import configparser # configparserのインスタンス化 config = configparser.ConfigParser() # 読込むiniファイルを指定 config.read("config.ini") ##### 関数 ##### # ファイルパスの取得 def get_path(): # グローバル変数 global file_path typ = [("Text","*.txt")] file_path = filedialog.askopenfilename(filetypes = typ) # iniへファイルパスを保存 def path_save(): config["Path"] = {"Text" : file_path} # iniファイルへ保存 with open("config.ini", "w") as file: config.write(file) ##### GUI ##### root = tk.Tk() root.geometry("300x100") # ボタン push_button = tk.Button(root, text = "Push", command = lambda:[get_path(), path_save()]) push_button.place(x = 30, y = 30) root.mainloop()まずは、設定ファイルの管理モジュールである「configparser」をインポートする必要があります。「config.ini」はテキストエディッタで、内容を記入せずに拡張子「.ini」で保存したものを使用すればOKです。
read()の引数で、読み込む設定ファイルのファイルパスを指定します。関数「get_path」内で「global file_path」としているのは、「file_path」をグローバル変数として扱うためです。通常、関数の中で宣言した変数は、その関数内でしか参照できません。しかし、変数「file_path」は、他の関数「path_save」でも使用するので、グローバル変数として宣言する必要があります。「filedialog」の使い方は、以前説明したので省略します。
関数「path_save」の「config["Path"] = {"Text" : file_path}」で、ファイルパスをiniファイルへどのように書き込むか指定しています。コードを実行した後、「config.ini」をテキストエディッタで開くと、以下のように、内容が保存されています。ここでは、ファイルパス「D:/test.txt」が保存されています。設定を書き込む際のコードは既出なので、説明を省略します。
「config.ini」に保存された値を、呼び出すには、以下のコードを実行します。ここでは、[Path]セクションの「Text」キーの値を取得しています。つまり、ここでは「D:/test.txt」という値が得られるはずです。
config["Path"].get("Text")
Tkinterの各種ウイジット
これまで紹介してきたウイジットの他に、スピンボックス、チェックボタン、ラジオボタン、コンボボックス、テキストボックスなどがあります。サンプルコードでは、[Push]ボタンをクリックすると、各ウイジットの設定値が、最後のエントリーボックスに表示されます。import tkinter as tk from tkinter import ttk ##### 関数 ##### # 各ボタンの値を取得 def value_get(): value = sp.get(), checkbtn.get(), radiobtn.get(), combo_dict[cb.get()], txtbox.get("1.0", "end") # エントリーボックスへ挿入 entrybox.insert(tk.END, value) ##### GUI ##### root = tk.Tk() root.geometry("300x180") # スピンボックス spinbox = tk.StringVar() spinbox.set(0) sp = ttk.Spinbox(root, textvariable = spinbox, from_=-5, to=5, width = 8) sp.pack() # チェックボタン checkbtn = tk.StringVar() checkbtn.set("NO") chk = ttk.Checkbutton(root, variable = checkbtn, text = "Check", onvalue = "OK", offvalue = "NO") chk.pack() # ラジオボタン radiobtn = tk.IntVar() rdo = ttk.Radiobutton(root, variable = radiobtn, text = "One", value = 1) rdo.pack() # コンボボックス combo_dict = {"One": "1", "Two": "2", "Three": "3", "Four": "4", "Five": "5"} cb = ttk.Combobox(root, values = list(combo_dict.keys()), state = "readonly") cb.pack() cb.current(0) # テキストボックス txtbox = tk.Text(root, width = 15, height = 1) txtbox.pack() # ボタン push_button = tk.Button(root, text = "Push", command = value_get) push_button.pack() # エントリーボックス entrybox = tk.Entry(width = 25) entrybox.pack() # ウインドウ状態の維持 root.mainloop()まず、はじめに「from tkinter import ttk」でTkinterのttkモジュールをインポートしています。これは、Tkinterでテーマ付きウィジェットへのアクセスを可能にするものです。下図は、上記のコードからスピンボックス、チェックボタン、ラジオボタンからttkテーマを排除した場合です。違いは微妙ですが、ttkを使用したほうが現代的なデザインになっています。全てのウイジットで使えるわけではないので、注意が必要です。
ウイジットの値はget()で取得できます。ここでは、便宜上、変数「value」に全てのウイジットの値を入れています。ですので、エントリーボックスには、値に{}が表示されます(値がタプル型で代入されているため)。{}を表示させたくない場合は、変数に複数の値を入れなければOKです。
各ウイジットの補足説明
上記のコードより、新しく登場したウイジットについて補足説明します。# スピンボックス
set()で初期値(アプリケーション起動時の値)を指定します。textvariableは、スピンボックスの値を受け取る変数を指定します。「from_」と「to」で下限と上限値を指定します。
# スピンボックス spinbox = tk.StringVar() spinbox.set(0) sp = ttk.Spinbox(root, textvariable = spinbox, from_=-5, to=5, width = 8) sp.pack()
# チェックボタン
set()で初期値(アプリケーション起動時の値)を指定します。variableは、チェックボタンの値を受け取る変数を指定します。「text」は、ボタン横の表示テキスト、「onvalue」と「offvalue」でON/OF時の値を指定します。
# チェックボタン checkbtn = tk.StringVar() checkbtn.set("NO") chk = ttk.Checkbutton(root, variable = checkbtn, text = "Check", onvalue = "OK", offvalue = "NO") chk.pack()
# ラジオボタン
variableは、ラジオボタンの値を受け取る変数を指定します。「text」は、ボタン横の表示テキスト、「value」はONの時の値を指定します。
# ラジオボタン radiobtn = tk.IntVar() rdo = ttk.Radiobutton(root, variable = radiobtn, text = "One", value = 1) rdo.pack()
# コンボボックス
変数「combo_dict」に、コンボボックスの内容を辞書型(ディクショナリ)で代入しています。辞書に文字列(key)と数字(value)がセットになった要素を「:」で区分けしています。要素間は「,」のカンマ区切りで分割しています。variableは、コンボボックスに表示する値のリストを指定します。
通常、コンボボックスは、ユーザーが値を入力することも可能です。しかし、ここでは「state = "readonly"」とすることで、ユーザーへの値の書込みを禁止しています。
# コンボボックス combo_dict = {"One": "1", "Two": "2", "Three": "3", "Four": "4", "Five": "5"} cb = ttk.Combobox(root, values = list(combo_dict.keys()), state = "readonly") cb.pack() cb.current(0)
おわりに
今回は、ウインドウのオプション、メニューバー、新規ウインドウ、メッセージボックス、設定の保存、各種ウイジット(スピンボックス、チェックボタン、ラジオボタン、コンボボックス、テキストボックス)について、簡単なサンプルコードを紹介しました。次回につづきます!!
リンク
【関連記事】
Pythonではじめるアプリ開発 ①:Python環境構築編
Pythonではじめるアプリ開発 ②:Python GUI編 その1
Pythonではじめるアプリ開発 ③:Python GUI編 その2
Pythonではじめるアプリ開発 ④:関数編
Pythonではじめるアプリ開発 ⑤:テキスト処理編
Pythonではじめるアプリ開発 ⑥:完成編
Pythonではじめるアプリ開発 ⑦:デバッグ編
Pythonではじめるアプリ開発 ⑧:exe化編
Pythonではじめるアプリ開発 ⑩:改造編 その2(終)
コメント