"BOKU"のITな日常

BOKUが勉強したり、考えたことを頭の整理を兼ねてまとめてます。

pythonでWindowsのGUI画面を作る標準ライブラリ「tkinter」を使ってみる

f:id:arakan_no_boku:20200627132450p:plain

目次

はじめに

tkinter --- Tcl/Tk の Python インタフェース

PythonWindowsGUI画面を使う手軽な選択肢「tkinter」の話題です。

tkinterは、Python標準のGUIライブラリで、 Tcl/Tk の Python インタフェースです。

ja.wikipedia.org

GUIは古く感じるデザインで、設計が古いせいか、ちょっと癖があります。

でも、「ちょこっと試す」ためのGUIを構築するには便利なライブラリです。

今回は、よく使う以下のWidgetに絞って、ごくシンプルな入力画面を作ります。。

  • Entry : 1行テキスト入力(テキストボックス)
  • Text  : 複数行テキスト入力(テキストエリア)
  • OptionMenu : プルダウンメニュー
  • CheckButton : チェックボックス
  • Button : サブミットボタン

他にもいろいろあります。

必要になったら、こちらのドキュメントとかを参考にします。

docs.python.org 

レイアウトのめんどくささを軽減するクラスを作ってみる 

tkinterはレイアウトがめんどくさいです。

GUIの設計画面はありません。

配置する座標をX・Yの座標で指定して微調整が必要ですので。

なので、部品を1行ずつペタペタ書いていけば、それなりの画面になる使い方をするためのクラスを作ってみます。

class_tkinter_use.py

import tkinter as tk
from tkinter import messagebox


class Gui:
    def __init__(self, title='Demo window'):
        self.window_width = 640
        self.window_height = 480
        self.left_space = 20
        self.right_space = 30
        self.top_space = 20
        self.row_span = 50
        self.col_span = 10
        self.label_width = 80
        self.x = self.left_space
        self.y = self.top_space
        self.root = tk.Tk()
        self.root.title(title)
        self.root.geometry(str(self.window_width) +
                           "x" + str(self.window_height))
        self.parts_list = []

    def text_box(self, label):
        x = self.x
        y = self.y
        w = self.label_width
        pw = 80
        lb = tk.Label(text=label)
        lb.place(x=x, y=y)
        box = tk.Entry(width=pw)
        box.place(x=x + w + self.col_span, y=y)
        self.y = self.y + self.row_span
        return box

    def text_area(self, label):
        x = self.x
        y = self.y
        w = self.label_width
        pw = 68
        lb = tk.Label(text=label)
        lb.place(x=x, y=y)
        box = tk.Text(width=pw, height=6)
        box.place(x=x + w + self.col_span, y=y)
        self.y = self.y + self.row_span + 50
        return box

    def check_box(self, label, boolvar):
        x = self.x
        y = self.y
        w = self.label_width
        box = tk.Checkbutton(text=label, variable=boolvar)
        box.place(x=x + w + self.col_span, y=y)
        self.y = self.y + self.row_span
        return box

    def bool_var(self):
        return tk.BooleanVar()

    def combo_box(self, label, values, select):
        x = self.x
        y = self.y
        w = self.label_width
        lb = tk.Label(text=label)
        lb.place(x=x, y=y)
        optionList = values
        variable = tk.StringVar(self.root)
        variable.set(optionList[0])
        box = tk.OptionMenu(self.root, variable, *optionList, command=select)
        box.place(x=x + w + self.col_span, y=y)
        self.y = self.y + self.row_span
        return box

    def button(self, label, command):
        button = tk.Button(text=label, command=command)
        button.place(x=self.x, y=self.y)
        self.y = self.y + self.row_span
        return button

    def show(self):
        self.root.mainloop()

    def msgbox(self, msg1, msg2):
        messagebox.showinfo(msg1, msg2)

    def textindex1(self):
        return '1.0'

    def textindex2(self):
        return 'end -1c'

簡単に捕捉します。 

Windowsサイズ、左右トップの各マージンは固定にしています。

数字べた書きですが・・まあ、個人用なので。

self,xとself.yに「次に描画する部品の座標」を保持して、部品の描画後に更新します。

 

作成したクラスを使って簡単な画面をつくってみる

パーツをぺたぺたのひとつずつ配置し、ボタンを押したときに入力値を取得して、メッセージボックスに表示します。

ソースコードはこんな感じです。

import class_tkinter_use as gt


def button_click():
    s = t1.get() + "\n" + selected + "\n" + str(chkValue.get()) + \
        "\n" + t4.get(wdw.textindex1(), wdw.textindex2())
    wdw.msgbox("クリックイベント", s)


def select(value):
    global selected
    selected = value


wdw = gt.Gui()
t1 = wdw.text_box(label='入力部品1')
oplist = [
    "選択するもの1",
    "選択するもの2"
]
selected = oplist[0]
chkValue = wdw.bool_var()
chkValue.set(True)
t2 = wdw.combo_box(label='入力部品2', values=oplist, select=select)
t3 = wdw.check_box(label='入力部品3', boolvar=chkValue)
t4 = wdw.text_area(label='入力部品4')
b1 = wdw.button(label='実行ボタン', command=button_click)
wdw.show()

各部品をひとつずつ配置してます。 

実行すると、以下のような画面を表示します。

f:id:arakan_no_boku:20200628144444p:plain

適当に入力したり、選択しなおしてみます。

f:id:arakan_no_boku:20200628144748p:plain

実行ボタンを押してみます。

f:id:arakan_no_boku:20200628144915p:plain

入力値は、取得できているみたいです。 

データの取得補足:テキストボックス 

 ikinterのwidgetでデータを取得する方法を簡単にまとめておきます。

まず、1行入力のテキストボックス(Entry)は簡単です。

t1.get()

のように、get()を呼ぶだけです。

これが複数行テキスト入力(Text)になると、get()の引数に、開始行(index1)と終了行(index2)の指定が必要なのは、前に書きましたので飛ばします。

データの取得補足:プルダウンリスト

プルダウンリスト(OptionMenu)は、状態が変化したときに呼び出されるコールバック関数を用意して、その中でglobal変数に値をセットして、それを参照するみたいなことをする必要があります。

上記のソースなら、この部分です。

def select(value):
    global selected
    selected = value

なのでボタンクリックで参照しているのは、selectedなのです。 

データの取得補足:チェックボックス

チェックボックス(CheckButton)の場合は、状態をセットする参照用の変数を定義してやる必要があります。

それがこの部分です。

chkValue = wdw.bool_var()
chkValue.set(True)
t3 = wdw.check_box(label='入力部品3', var=chkValue)

この場合だと、チェックボックスが選択されたり、解除されたりしたときに、chkValueの値が変化します。

なので。

chkValue.get()

でとりだせているわけです。

とりあえず、適当なクラスですが、ちょっとした動作確認の画面には重宝してます。

今回はこんなところで。

ではでは。