MEMO blog

主に自分用のメモです

Tkinter

大体がほぼ使い捨てのスクリプトレベルのものしか書かないけど、GUIがあった方がいいときもあるかなぁと思いつつ、久しぶりに調べてみたので記録する。

ちゃんとしたGUIアプリにするならイベントとかデータの受け渡しなんかも考えないといけない気がするし、実際に使うときはまだまだ調べながらになるけど、まあとりあえずで作るとき用のメモとしてはこんなものか。

参考:

メモ:

  • Tk()でメインウィンドウを生成して、その下に各種widgetを配置していく。
  • widgeはテーマ付きのttkの方で生成しとくと、スタイル変更に対応できる感じぽい
  • widgeはbutton()などで生成するだけでなく、grid()でちゃんと配置しよう
  • bind()でイベントに対するアクションが設定できるが、コールバック関数にはイベントも引数として渡されるので、*argなどでイベントも受け取れるようにしておくといいかな
import sys
import tkinter as tk
import tkinter.filedialog
import tkinter.messagebox
import tkinter.ttk as ttk
import logging

log_format = "[%(levelname)s]%(name)s, %(filename)s, line %(lineno)d, %(funcName)s(), %(message)s"
logging.basicConfig(level=logging.INFO, format=log_format)
#logger = logging.getLogger(__name__)


class TkMainWindow:
    def __init__(self):

        self._logger = logging.getLogger(__name__)

        self._root = tk.Tk()
        self._root.title("test_window")

        self._set_menu()
        self._set_widgets()
        self._set_event_action()

    def _set_widgets(self):
        root = self._root
        root.rowconfigure(0, weight=1)
        root.columnconfigure(0, weight=1)

        # style
        s = ttk.Style()
        # s.theme_use("alt")
        s.configure('MyWidget.TFrame', background='#ccccff')

        # main_frame
        main_frame = ttk.Frame(root, padding=(10), style="MyWidget.TFrame")
        main_frame.grid(row=0, column=0, sticky=(tk.N, tk.W, tk.E, tk.S))

        main_frame.columnconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(0, weight=1)


        # widgets
        b1 = ttk.Button(main_frame, text="Button1")
        b1.grid(row=0, column=0, padx=10)
        b2 = ttk.Button(main_frame, text="Button2",
                        command=self._button_action)
        b2.grid(row=0, column=1, padx=10)

    def _set_menu(self):
        root = self._root

        # menu bar
        menubar = tk.Menu(root)
        root['menu'] = menubar

        # menu items
        menu_file = tk.Menu(menubar, tearoff=0)
        menu_file_sub = tk.Menu(menu_file, tearoff=0)

        menu_edit = tk.Menu(menubar, tearoff=0)

         # File
        menubar.add_cascade(menu=menu_file, label='File')
        menu_file.add_command(label="New")
        menu_file.add_command(label="Open", command=self._open_file)
        menu_file.add_cascade(menu=menu_file_sub, label="sub")
        menu_file_sub.add_command(label="sub1")
        menu_file_sub.add_command(label="sub2")
        menu_file.add_separator()
        menu_file.add_command(label="Close", command=self._close_window)
        # Edit
        menubar.add_cascade(menu=menu_edit, label='Edit')
        menu_edit.add_command(label="Edit1")
        menu_edit.add_command(label="Edit2")

    def _set_event_action(self):
        root = self._root
        # (注意)bindされた関数には、引数としてイベントオブジェクトが渡される
        root.bind('<Control-q>', self._close_window)

    def _open_file(self):
        self._logger.info("call openfile(): return {}".format(
            tk.filedialog.askopenfilename()))

    def _button_action(self):
        self._logger.info("Button pushed")

    def _close_window(self, *args):
        self._logger.info("args: {}".format(args))
        self._logger.info("Close window")
        self._root.destroy()

    def run(self):
        self._root.mainloop()


def main_function():

    app = TkMainWindow()
    app.run()

    return 0


if __name__ == "__main__":

    main_function()
    sys.exit(0)

f:id:tee52335:20201026013503p:plain

メモその2_widgetたち:

widget Description
Frame -
Label 文字や画像の配置
Button 押したときのアクションは関数オブジェクトを渡す
Checkbutton -
Radiobutton -
Entry テキストボックス
Combobox プルダウンリスト
Listbox 一覧リスト
Scrollbar -
Text テキストボックス
Scale スライダー
Spinbox 1 個ずつ動かす系
Progressbar -
Separator 仕切り線
LabelFrame ラベル付き Frame
Panedwindow
Notebook タブわけ
Treeview