【プログラミング】PythonのGUI画面をお試しで作ってみる(tkinter)

Python

1.PythonのGUI用ライブラリ

今回、Pythonに標準で搭載されているライブラリである「tkinter」を使ってGUIの画面を作ってみました。
CUIではコマンドライン上で処理を実行していく形になりますが、GUIの画面を使う事で「メニューを選択する」「ボタンをクリックする」といった画面上の操作が可能となります。

せっかくならコマンドライン上でプログラムを動かすより、画面上でマウス操作して動かす方が面白いですよね。
なので、この「tkinter」に触れてみることで、PythonによるGUIアプリ作成の第一歩にしてみようと思います。

2.ライブラリ「tkinter」を用いたPythonプログラム

下記のプログラムは、単純にいくつかの機能を配置しただけの簡単な画面作成プログラムです。
機能の説明用に適当に配置しただけなので、アプリとして綺麗に動くものではないですが、そこはご了承ください。

import tkinter as tk

# グローバル変数の定義
entry = None            # 入力エリアのオブジェクト保持用
lbl = None              # ラベルのオブジェクト保持用
opStatus = None         # オプションメニューの状態保持用
lstbx = None            # リストボックスのオブジェクト保持用


#==============================================================================================        
# 画面を描画する関数        
#==============================================================================================        

def run():
        # グローバル変数を使用するための記述
        global entry, lbl, lstbx, opStatus

        # メインウィンドウを作成
        mainWindow = tk.Tk()
        # ウィンドウのサイズを設定
        mainWindow.geometry('550x700')
        # ウィンドウのタイトルを設定
        mainWindow.title('GUI_Form')
        # フォントの用意
        font=('Helevetica', 14)
        font_lbx=('Helevetica', 11)

        # メニューバーの作成
        menubar = tk.Menu(mainWindow)
        mainWindow.config(menu=menubar)

        # 「ファイル」メニュー
        filemenu = tk.Menu(menubar)
        menubar.add_cascade(label='ファイル', menu=filemenu)
        filemenu.add_command(label='閉じる', command=mainWindow.destroy)

        # 「オプション」メニュー
        opStatus = tk.IntVar()
        optionmenu = tk.Menu(menubar)
        menubar.add_cascade(label='オプション', menu=optionmenu)

        optionmenu.add_radiobutton(
            label='オプション1',                  # 「オプション」メニュー(1つ目)
            variable = opStatus,                 # 選択時の値を格納するオブジェクト
            value = 0                             # opSstatusの値を0にする
        )
        
        optionmenu.add_radiobutton(
            label='オプション2',                  # 「オプション」メニュー(2つ目)
            variable = opStatus,                 # 選択時の値を格納するオブジェクト
            value = 1                             # opSstatusの値を1にする
        )

        # キャンバスの作成
        canvas = tk.Canvas(
                    mainWindow,                   # メインウィンドウに配置
                    width = 500,                  # 幅を設定
                    height = 300,                 # 高さを設定
                    relief = tk.RIDGE,            # 枠線を設定
                    bd = 2                        # 枠線の幅を設定
                 )
        canvas.place(x=0, y=0)

        img = tk.PhotoImage(file = 'flower.gif')  # 表示するイメージをイメージオブジェクトに設定
        canvas.create_image(                      # キャンバス上への配置設定
            0,                                    # x座標
            0,                                    # y座標
            image = img,                          # 配置するイメージオブジェクトを指定
            anchor = tk.NW                        # 配置の起点となる位置を指定
        )

        #ラベルを作成
        lbl = tk.Label(
                    mainWindow,                   # メインウィンドウに配置
                    width = 50,                   # 幅を設定
                    height = 3,                   # 高さを設定
                    bg = 'blue',                  # 背景色を設定
                    font = font,                  # フォントを設定
                    relief = tk.RIDGE,            # 枠線の種類を設定
                    bd = 2,                       # 枠線の幅を設定
                    text = u'ラベル' 
                 )


        # フレームの作成
        frame = tk.Frame(
                    mainWindow,                   # メインウィンドウに配置
                    relief = tk.RIDGE,            # 枠線の種類を設定
                    borderwidth = 4               # 枠線の幅を設定
                 )
            
        # 入力ボックスの作成
        entry = tk.Entry(
                    frame,                        # フレームに配置
                    width = 40,                   # 幅を設定
                    font = font                   # フォントを設定
                 )
        entry.pack(side = tk.LEFT)                # フレームへの配置位置を設定
        entry.focus_set()                         # 入力ボックスにフォーカスを当てる

        # ボタンの作成
        button = tk.Button(
                    frame,                        # フレームに配置
                    width = 15,                   # 幅を設定
                    text = 'ボタン',              # ボタンに表示するテキストを設定
                    command = btnAction           # クリック時にbtnAction()関数を呼ぶ
                )
        button.pack(side = tk.LEFT)               # フレームへの配置位置を設定


        # リストボックスを作成
        lstbx = tk.Listbox(
                    mainWindow,                   # メインウィンドウに配置
                    width = 63,                   # 幅を設定
                    height = 15,                  # 高さを設定
                    bd = 2,                       # 枠線の幅を設定
                    font = font_lbx               # フォントを設定
                )

        # 縦のスクロールバーを生成
        sb1 = tk.Scrollbar(
                    mainWindow,                   # メインウィンドウに配置
                    orient = tk.VERTICAL,         # 縦方向のスクロールバーにする
                    command = lstbx.yview         # スクロール時にListboxのyview()メソッドを呼ぶ
                )


        # 横のスクロールバーを生成
        sb2 = tk.Scrollbar(
                    mainWindow,                   # メインウィンドウに配置
                    orient = tk.HORIZONTAL,       # 横方向のスクロールバーにする
                    command = lstbx.xview         # スクロール時にListboxのxview()メソッドを呼ぶ
                )

        # リストボックスとスクロールバーを連動させる
        lstbx.configure(yscrollcommand = sb1.set)
        lstbx.configure(xscrollcommand = sb2.set)

        # grid()で画面上に各要素を配置
        canvas.grid(row = 0, column = 0)
        lbl.grid(row = 1, column = 0)
        lstbx.grid(row = 2, column = 0)
        sb1.grid(row = 2, column = 1, sticky = tk.NS)
        sb2.grid(row = 3, column = 0, sticky = tk.EW)
        frame.grid(row = 4, column = 0)

        # メインループ
        mainWindow.mainloop()


#==============================================================================================        
# ボタンクリック時の動作を定義した関数        
#==============================================================================================        
def btnAction():
    value = entry.get()
    lstbx.insert(tk.END, value)

    
#==============================================================================================        
# プログラムの起点        
#==============================================================================================        
if __name__ == '__main__':
    run()

任意のフォルダを作成し、そこに上記プログラムを配置します。
因みに、64行目には以下のgifファイルを読み込む処理もありますので、同じフォルダ内に同時に配置しておきます。

flower.gif

これらの準備をした状態で、先程のプログラムを実行してみましょう。
すると、下記の画面が表示されます。

↓↓↓

すみません、「何だ、この画面?」と思ったかもしれませんが、今回はお試しで適当に作っただけなので、そこはご勘弁を。。。
何の脈絡もない並びになっていますが、こんな機能があるよ、というのを紹介するのが本記事の目的なので、画面全体の構成はひとまず度外視しています。

次章にて、各機能の説明をしていきます。

3.各機能の説明

上記のPythonプログラム「guiForm.py」について、各機能の説明をしていきたいと思います。
そのままコピペして実行すれば画面は出力されますが、一つ一つの機能を理解する事で、今後の応用に繋がっていきますので、見ていきましょう。

① tkinter のインポート

import tkinter as tk

まず初めに、GUI作成用のライブラリである「tkinter」をインポートする必要があります。
これを行わないと何も始まりませんので、必ず1行目に記述してください。
なお、「as tk」を付与しておくことで、ソース内でtkinterを「tk」と表記することができます。

② グローバル変数の定義

entry = None            # 入力エリアのオブジェクト保持用
lbl = None              # ラベルのオブジェクト保持用
opStatus = None         # オプションメニューの状態保持用
lstbx = None            # リストボックスのオブジェクト保持用

こちらは、後続で説明する画面描画用の関数で、各オブジェクトを保持するための変数です。
複数の関数内で使用しますので、関数の外で「グローバル変数」として定義しておきます。
ひとまずは、初期値としてNoneを設定します。(※Pythonでは、初期値はnullではなくNoneとして設定)

③ runメソッドの作成 & global文によるクローバル変数宣言

def run():
     # グローバル変数を使用するための記述
     global entry, lbl, lstbx, opStatus

②でグローバル変数の定義が出来たので、次は画面描画のための「run」メソッドを作成します。
この後に説明する各機能を実装した後にこのrunメソッドを呼び出すことで、画面の描画が実行されます。

runメソッドでは、まずgrobal文にて、指定した変数がグローバル変数であることを宣言してあげる必要があります。
この宣言をしておかないと、これらの変数は各メソッド内で参照はできても値の代入が出来なくなってしまいますので、注意してください。

④ メインウィンドウ作成

# メインウィンドウを作成
mainWindow = tk.Tk()
# ウィンドウのサイズを設定
mainWindow.geometry('550x700')
# ウィンドウのタイトルを設定
mainWindow.title('GUI_Form')

始めにtkinter(tk)のTk()メソッドを呼び出します。
この処理で、tkクラスのオブジェクトを生成し、変数「mainWindow」に設定します。

この「mainWindow」が名前の通りメインウィンドウとして機能します。
ここに、画面内の各要素を配置していくイメージです。

まずは、ウィンドウサイズ、タイトルを上記の通り設定しましょう。

# フォントの用意
font=('Helevetica', 14)
font_lbx=('Helevetica', 11)

こちらは画面内で使用するフォントの定義です。
この後の各要素の設定時に使用しますので、ここでは最初に「font」「font_lbx」の2種類の定義を行っておきます。

対象フォント+サイズをカッコ内に設定し、各変数に代入してください。
(因みに、’Helevetica’は世界で最も多く使われているフォントとの事です)

ここまでの実装で、以下のようなウィンドウが作成されます。

⑤ メニューバー作成

# メニューバーの作成
menubar = tk.Menu(mainWindow)
mainWindow.config(menu=menubar)

④で作成したメインウィンドウ内に、メニューバーを配置します。
まずはメインウィンドウのオブジェクト(※mainWindow)を引数にしてMenuメソッドを呼び出し、「menubar」に代入してメニューオブジェクトとして生成します。


その後は、menuberをmenuオプションに設定した状態を引数として、configメソッドを呼び出します。
ここまでの手順で、メインウィンドウ上にメニューバーが設定されます。

# 「ファイル」メニュー
filemenu = tk.Menu(menubar)
menubar.add_cascade(label='ファイル', menu=filemenu)
filemenu.add_command(label='閉じる', command=mainWindow.destroy)

「ファイル」メニューをメニューバーに追加する場合は、メニューバーのオブジェクト(menubar)を引数にMenu()メソッドを呼び出し、生成したMenuオブジェクトを「filemenu」に代入します。
その後は、menuオプションに先ほどの「filemenu」を設定してadd_cascade()メソッドを呼び出せば、「ファイル」メニューを表示させます。

更に、「ファイル」メニュー配下に「閉じる」を配置します。
commandオプションに「mainWindow.destroy」を設定することで、「閉じる」を選ぶとウィンドウが閉じるようになります。

# 「オプション」メニュー
opStatus = tk.IntVar()
optionmenu = tk.Menu(menubar)
menubar.add_cascade(label='オプション', menu=optionmenu)

今回は、ファイルメニューのほかに「オプション」メニューも作成してみます。(上記参照)
作成方法は
先程の「ファイル」メニューと同じような感じなので、まずはその内容を参考に作ってみてください。

optionmenu.add_radiobutton(
    label='オプション1',                   # 「オプション」メニュー(1つ目)
    variable = opStatus,                 # 選択時の値を格納するオブジェクト
    value = 0                             # opSstatusの値を0にする
)
        
optionmenu.add_radiobutton(
    label='オプション2',                   # 「オプション」メニュー(2つ目)
    variable = opStatus,                 # 選択時の値を格納するオブジェクト
    value = 1                             # opSstatusの値を1にする
)

「オプション」メニューも、「ファイル」メニューと同様、配下のメニューを用意しましょう。

上記はサブメニューである「オプション1」「オプション2」を作成する実装です。
「オプション」メニューのオブジェクトである「optionmenu」に対し、「add_radiobutton」メソッドを2回呼び出しています。
これにより、「オプション」の配下に「オプション1」「オプション2」のサブメニューが配置され、それらはラジオボタンと同様に動作します。
(選択した方にチェックが付きます)

上記の実装例では、同時にopStatusに ‘0’ or ‘1’を設定させています。
この例では数値をセットしているだけで特にその変数は使用していませんが、判定処理として利用する事も可能です。


因みに、メニューアイテムを追加するメソッドは、主に以下の種類があります。参考にしてみて下さい。

メソッド名説明
add_cascade()メニューアイテムを追加する。
add_checkbutton()チェックボタン(2つの何れかを選択可能)の機能を持つサブメニューを追加する。
add_command()commandオプションで指定した関数、メソッドを実行する。
add_radiobutton()ラジオボタン(複数の中から何れかを選択可能)の機能を持つサブメニューを追加する。
add_separator()区切り線を追加する。

ここまでの⑤の実装で作成されるのは、以下の部分です。

⑥ キャンバスの作成

# キャンバスの作成
canvas = tk.Canvas(
            mainWindow,                   # メインウィンドウに配置
            width = 500,                  # 幅を設定
            height = 300,                 # 高さを設定
            relief = tk.RIDGE,            # 枠線を設定
            bd = 2                        # 枠線の幅を設定
         )
canvas.place(x=0, y=0)

⑤まで実施しますと、メインウィンドウにタイトルとメニューを配置することができます。
ここからは、メインウィンドウの中身を配置していきます。

まずはtkinterのウィジェットであるキャンバスの作成を行いましょう。
Canvasウィジェットは、円や直線、楕円といった図形や、画像ファイルを配置できる領域となります。


上記の実装のように、メインウィンドウ、幅、高さ、枠線等を引数として設定し、Canvas()メソッドを呼び出すことでオブジェクトが生成できます。
メインウィンドウ内の位置を引数としてplace()メソッドを呼び出せば、配置場所の指定も可能です。

なお、今回はこのCanvasに画像ファイルを貼り付けています。                   

img = tk.PhotoImage(file = 'flower.gif')  # 表示するイメージをイメージオブジェクトに設定
canvas.create_image(                      # キャンバス上への配置設定
    0,                                    # x座標
    0,                                    # y座標
    image = img,                          # 配置するイメージオブジェクトを指定
    anchor = tk.NW                        # 配置の起点となる位置を指定
)

読み込ませる対象の画像ファイルをfileに代入し、それを引数としてPhotoImage()メソッドを呼び出してください。
ここで生成したオブジェクトである「img」を、更にcreate_image()メソッドの引数とします。

他にも、Canvas配置のx,y座標やCanvasに貼り付ける画像の起点となる位置(anchor)を併せて引数として設定し、create_image()メソッドを呼び出すことで、キャンバスが作成されます。

なお、注意点としては、PhotoImage()メソッドの引数として使用できる画像形式は、GIF、PGM、PPM、PNGのみです。JPEGは使用できませんので、気を付けて下さい。

<補足>
anchorオプションですが、上記の実装では、「tk.NW」を指定しています。これは、起点がNorthWest(北西)、つまり左上になる、という意味です。

これが右上起点ですと、NE(NorthEast/北東)となったりしますので、色々と試してみてください。
他にも、以下の指定ができますので、試してみて下さい。

ここまでの⑥の実装で作成されるのは、以下の部分です。

⑦ ラベルの作成

#ラベルを作成
lbl = tk.Label(
            mainWindow,                   # メインウィンドウに配置
            width = 50,                   # 幅を設定
            height = 3,                   # 高さを設定
            bg = 'blue',                  # 背景色を設定
            font = font,                  # フォントを設定
            relief = tk.RIDGE,            # 枠線の種類を設定
            bd = 2,                       # 枠線の幅を設定
            text = u'ラベル' 
         )

単純に文字を貼り付けたい場合は、「ラベル」を作成し、配置します。
ラベルの設定内容(幅、高さ、背景色など)を引数としてLabel()メソッドを呼び出してください。
ここで生成したオブジェクトである「lbl」がラベルオブジェクトとなります。

因みに、上記の
fontオプションに設定している「font」は、「④ メインウィンドウ作成」で予め設定しておいたフォントとなります。

font=('Helevetica', 14)

↑これですね。

これらの指定で、以下の通りのラベルが作成されます。
幅と高さは指定の通り。背景色[bg]はblue(青)、枠線[relief]はRIDGE(土手)、文字は「ラベル」といった、引数の指定の通りのラベルが作成、配置されます。

⑧ フレームの作成

ここまでは、メインウィンドウ上にキャンバスやラベルといった要素を直接配置してきました。
次は、その中に更に小さい枠を作成し、複数の要素を一纏めにして配置していきます。

この小さい枠を「フレーム」といいます。

# フレームの作成
frame = tk.Frame(
            mainWindow,                   # メインウィンドウに配置
            relief = tk.RIDGE,            # 枠線の種類を設定
            borderwidth = 4               # 枠線の幅を設定
         )

このように、枠線等を引数に設定した状態でFrame()メソッドを呼び出し生成したオブジェクトメインウィンドウ上に配置します。
まだこの状態では、フレームは空っぽの状態なので、ここに更に要素を追加していきましょう。

# 入力ボックスの作成
entry = tk.Entry(
            frame,                        # フレームに配置
            width = 40,                   # 幅を設定
            font = font                   # フォントを設定
         )
entry.pack(side = tk.LEFT)                # フレームへの配置位置を設定
entry.focus_set()                         # 入力ボックスにフォーカスを当てる

# ボタンの作成
button = tk.Button(
            frame,                        # フレームに配置
            width = 15,                   # 幅を設定
            text = 'ボタン',              # ボタンに表示するテキストを設定
            command = btnAction           # クリック時にbtnAction()関数を呼ぶ
        )
button.pack(side = tk.LEFT)               # フレームへの配置位置を設定

フレーム内に「入力ボックス」「ボタン」を左詰めで配置します。
オブジェクトの生成は、他と同様にEntry()、Button()といった各メソッドを呼び出すことで実行されます。

これにより、以下のようなフレームが完成します。

因みに、ボタンをクリックした際に起動する関数「btnAction()」については、後述します。

⑨ リストボックスの作成(スクロールバー付)

次は、リストボックスをウィンドウ上に配置します。
リストボックスとは、文字列を選択可能な複数の”行”として表示できるエリアとなります。
作成方法は、以下の通りです。

# リストボックスを作成
lstbx = tk.Listbox(
            mainWindow,                   # メインウィンドウに配置
            width = 63,                   # 幅を設定
            height = 15,                  # 高さを設定
            bd = 2,                       # 枠線の幅を設定
            font = font_lbx               # フォントを設定
        )

これまでと同様の作成方法でListbox()メソッドを呼び出すことで、オブジェクトが生成されます。
なお、ここで指定している「font_lbx」は、④で実装したリストボックス用のフォント設定です。


これだけでもリストボックスは作成できますが、文字列が指定幅に収まらない、そして行数が多くなってしまうという事象も考えられます。
よって、縦横のスクロールバーも
一緒に付けてみましょう。

# 縦のスクロールバーを生成
sb1 = tk.Scrollbar(
            mainWindow,                   # メインウィンドウに配置
            orient = tk.VERTICAL,         # 縦方向のスクロールバーにする
            command = lstbx.yview         # スクロール時にListboxのyview()メソッドを呼ぶ
        )

# 横のスクロールバーを生成
sb2 = tk.Scrollbar(
            mainWindow,                   # メインウィンドウに配置
            orient = tk.HORIZONTAL,       # 横方向のスクロールバーにする
            command = lstbx.xview         # スクロール時にListboxのxview()メソッドを呼ぶ
        )

# リストボックスとスクロールバーを連動させる
lstbx.configure(yscrollcommand = sb1.set)
lstbx.configure(xscrollcommand = sb2.set)

このように、縦、及び横のスクロールバーをオブジェクトとして作成し、リストボックスのオブジェクト[lstbx]に連動させることで、リストボックスの文字列が多くなった、若しくは行数が増えた場合にスクロールバーが機能してくれます。

⑩ メインウィンドウ上に要素を配置

ここまでに各要素のオブジェクトを生成してきましたが、ここで初めて、メインウィンドウ上に配置するための実装を行います。

# grid()で画面上に各要素を配置
canvas.grid(row = 0, column = 0)
lbl.grid(row = 1, column = 0)
lstbx.grid(row = 2, column = 0)
sb1.grid(row = 2, column = 1, sticky = tk.NS)
sb2.grid(row = 3, column = 0, sticky = tk.EW)
frame.grid(row = 4, column = 0)

配置方法はいくつかありますが、今回の例ではgrid()による配置をしていこうと思います。

上記実装内容を見ての通り、grid()の引数として[row]、[column]があります。
[row]は行数、[column]は列数を指定します。

実際の出力画面と照らし合わせると、

こんなイメージです。
他にもplace()、pack()といった位置決め方法もありますので、是非色々と試してみて下さい。

#==============================================================================================        
# プログラムの起点        
#==============================================================================================        
if __name__ == '__main__':
    run()

最後に、上記の実装をしておくことで、このプログラムを実行した際に、run()メソッドを呼び出してくれます。
Pythonでは、対象のプログラムを実行すると「__name__」に「’__main__’」という値が代入されるため、そのままrun()を呼び出してくれるという訳です。
(先頭と末尾にアンダースコア(__)が付いている変数は、Pythonが使う変数として予約されているものです)

4.画面を動かしてみる

これで画面が完成したのですが、せっかく入力ボックスやボタンが配置されていますので、ちょっと動きを付けてみましょう。

#==============================================================================================        
# ボタンクリック時の動作を定義した関数        
#==============================================================================================        
def btnAction():
    value = entry.get()
    lstbx.insert(tk.END, value)

ボタン配置時に、クリックするとbtnAction()関数を呼び出す実装としていましたが、上記がその関数の内容です。
入力ボックスに文字列を入力後にボタンをクリックすると、リストボックスに入力した文字列が表示される、という処理になります。

        ↓↓↓

こんな感じで、入力ボックスの文字列がリストボックスに転記されます。
ボタンを押すたびに、新しい行としてリストボックスに追加されていきます。

まとめ

今回、Pythonのライブラリである「tkinter」を利用して、画面操作可能なアプリ(と呼ぶには余りにお粗末ですが。。。)を作ってみました。
指定したオプションはほんの一部であり、他にも様々な設定ができますので、今回のサンプルを参考に、是非いろいろと試しながらアプリを作ってみて下さい。
(今回はここまで)

お読みいただき、有難うございました!

コメント

タイトルとURLをコピーしました