TkinterでGUIアプリケーション開発 02 フレームとボタンと画像【Python3】

Python

TkinterでGUIアプリケーション開発の2記事目になります。

今回はウィンドウ内部を機能別に分ける際に使われるフレームと、これまたGUIアプリに必須なボタンを扱っていきます。

前回の記事ではTkinterライブラリのインストールから、ウィンドウとラベルについて扱いましたので、初めてこの記事にたどり着いた方は、そちらから見てもらうと理解しやすいと思います。

Tkinterとは?

TkinterはPythonに標準搭載されているGUIアプリケーションライブラリです。

TkinterのTkは、Tcl/TkのTkの部分を指しています。

Tcl/Tkは、スクリプト言語であるTclとGUIツールキットであるTkからなる、GUI開発環境のことです。

少しややこしいですが、Tcl言語のGUIツールであるTkをPythonでも使えるようにしたのがTkinterです。

ちなみにPython以外にPerlやRubyでもTkを使ったGUIアプリの開発が行えます。

OSに関しても、Windows、Mac OS、Linuxなどで利用可能な、汎用性の高いツールになっています。

フレームの設定

フレームは、ウィンドウの分割だと考えてもらうとわかりやすいと思います。

例えば、ファイルを選択して、列選択やグラフの種類を決めて、グラフ表示をするアプリがあるとします。

この時、データの入力エリアと、可視化するエリアの2つに大別されると思いますが、それぞれにボタンやドロップダウンがあったり機能が付随してきます。

フレームを分けてやることで、GUI部分を書く側は書きやすく、ユーザー側は見やすくなります。

フレームにはいくつか種類がありますので、この章では各フレームの特徴をまとめています。

フレーム

最もシンプルな形で、要素の位置関係はpack()内部に記述します。

位置関係を決めにくいのであまりオススメはできないかと思います。

グリッドフレーム

グリッドフレームは、要素を1単位として、(0,0)の要素を基準に、その要素の「隣」や「上」「下」などのイメージで記述していきます。

xはcolumn = 〇、yはrow = 〇となります。

整列が非常にカンタンで、(私のような)デザインセンスのない人にオススメです。

ラベルフレーム

ラベルフレームは、グリッドフレームにラベルを付けて、それっぽく四角の囲み線が入ったフレームです。

私のお気に入りで、特に制約がない限りこれでいいのではと思っています。

ここまでテキストで説明しましたが、実際の表示とソースコードはこちら。

# tkinter_basic_04.py
# フレーム

import tkinter 
from tkinter import BOTH

# windowの作成
root = tkinter.Tk()
root.title("Frame_Basics")
root.iconbitmap("favicon.ico")
root.geometry("400x700") # ×ではなく、アルファベットのx
root.resizable(0,0) # 00で上下リサイズできなくなる
root.config(bg = "white") # バックグラウンドカラーを変更する

# フレームの定義

pack_frame = tkinter.Frame(root, bg = "firebrick")
grid_frame_1 = tkinter.Frame(root, bg = "royalblue")
# フレームに名前をつけれるイメージ
grid_frame_2 = tkinter.LabelFrame(root, text = "ラベルフレームの作成",borderwidth = 5)

# フレームをパックする
pack_frame.pack(fill = BOTH, expand = True)
grid_frame_1.pack(fill = BOTH, expand = True)
grid_frame_2.pack(fill = BOTH, expand = True)
# expandが3つなので、ウィンドウを③分割している

# フレームの中に入れてみる
tkinter.Label(pack_frame, text = "フレーム内にラベル").pack()
tkinter.Label(pack_frame, text = "フレーム内にラベル").pack()
tkinter.Label(pack_frame, text = "フレーム内にラベル").pack()

# グリッドフレームの中に入れてみる
tkinter.Label(grid_frame_1, text = "グリッドフレーム内にラベル").grid(row = 0, column = 0)
tkinter.Label(grid_frame_1, text = "グリッドフレーム内にラベル").grid(row = 2, column = 1)
tkinter.Label(grid_frame_1, text = "グリッドフレーム内にラベル").grid(row = 1, column = 2)

# ラベルフレームの中に入れてみる
tkinter.Label(grid_frame_2, text = "ラベルフレーム内にラベル").grid(row = 0, column = 0)
tkinter.Label(grid_frame_2, text = "ラベルフレーム内にラベル").grid(row = 2, column = 1)
tkinter.Label(grid_frame_2, text = "ラベルフレーム内にラベル").grid(row = 1, column = 2)

# rootの実行
root.mainloop()

ボタンの設定

以下のコードでは、文字列を入力するフォームを用意して、入力部分と出力部分にフレームを分割して色分けや名前付けなどを行っていますので確認していきましょう。

ボタンの設定は以下のようになります。

※私の設定方法だと、詳細設定(フォントなど)は全てconfig内部に入れるようにしています。設定漏れなどを回避するためにコードの可読性を重視しているためです。

ボタン変数=tkinter.button(ボタンの設置フレーム)

ボタン変数.config(command =クリック時の処理関数)

ボタン変数.config(width = 幅,height = 高さ)

ボタン変数.config(bg=バックグラウンドカラー,fg = 文字カラー)

などなど

本来であればまだまだ設定できる項目はありますが、最も重要なのはコマンドでしょう。

クリック時に動作するアクションを定義しておく必要があるため、最低限のボタンを作る場合は、設置場所とコマンドだけ与えてしまえば大丈夫です。

最後に、packやgridを書いて表示させればボタンのできあがりです。

ここでは、入力フォームにテキストを入れて、「Test Button」をクリックすると、下側の青いフレーム内にテキストを表示させ、入力フォームの中身を削除するようにしています。

# tkinter_basic_05.py
# エントリーフォームの作成

import tkinter 
from tkinter import BOTH
# インプットフレーム内部を削除する
from tkinter import END

# ボタンをクリックした時の機能を記述する
def make_label():
    # ラベルをoutput_frameに記述する
    # text_entry.get()でtext_entryに記述された内容を取得する
    text = tkinter.Label(output_frame)
    text.config(text = text_entry.get())
    text.config(bg = "blue")
    text.config(fg = "white")
    
    # 記述を実行
    text.pack()

    text_entry.delete(0, END)

# windowの作成
root = tkinter.Tk()
root.title("Entry_Basics")
root.iconbitmap("favicon.ico")
root.geometry("400x700") # ×ではなく、アルファベットのx
root.resizable(0,0) # 00で上下リサイズできなくなる
root.config(bg = "white") # バックグラウンドカラーを変更する

# フレームの定義
input_frame = tkinter.Frame(root, bg = "firebrick", width = 400, height = 300)
output_frame = tkinter.Frame(root, bg = "royalblue", width = 400, height = 100)
input_frame.pack(padx = 5, pady = 10)
output_frame.pack(padx = 5, pady = 10)

# インプットフレーム
text_entry = tkinter.Entry(input_frame, width = 30)
text_entry.grid(row = 0, column = 0, padx = 5, pady = 5)
input_frame.grid_propagate(0)

# ボタンをインプットフレームの横に
print_button = tkinter.Button(input_frame, text = "Test Button")
print_button.config(command = make_label)
print_button.grid(row = 0, column = 1, padx = 5, pady = 5, ipadx = 30)
# フレームのサイズをキープする
output_frame.pack_propagate(0)


# rootの実行
root.mainloop()

ラジオボタンの設定

ラジオボタンは、複数のカテゴリーから1つを選択させる際に使われる丸いボタンのことです。

例:最終学歴は?

  • 大卒
  • 院卒
  • その他

のように答えが必ず1つに定まる(排他的)な質問に対して使われます。

逆に、複数の答えがありえる(利用したことのある検索エンジンは?)質問にはチェックボックスが使われることが多いです。

ラジオボタンの設定は少しややこしいですが、基本的に下記のコードのコピペでいけるはずです。

手順は

  1. ラジオボタンを選択肢の数作成
  2. ラジオボタンにvalue変数で数字を与える(後でif文で処理の分岐に使います)(variableでは、valueの値をなnumber変数に格納して後のボタンクリック時に渡す動きをします。)
  3. イベント駆動用のボタンを設置
  4. ボタンクリック時に発生するコマンドを定義する(下記コードではmake_labelです)
  5. コマンドの処理に、ラジオボタンのnumber値によって処理の分岐を作る

ラジオボタンを設置した時は、目に見える選択肢だけでなく、クリック時に値を渡す、valueとvariableの定義が必要なことに注意してください。

# ラジオボタンの作成

import tkinter 
# 整数型を保持する
from tkinter import IntVar


def make_label():
    if number.get() == 1:
        num_label = tkinter.Label(output_frame, text = "1番が押されています")
    elif number.get() == 2:
        num_label = tkinter.Label(output_frame, text = "2番が押されています")
    elif number.get() == 3:
        num_label = tkinter.Label(output_frame, text = "3番が押されています")
    num_label.pack()
# windowの作成
root = tkinter.Tk()
root.title("Radio_Button_Basics")
root.iconbitmap("favicon.ico")
root.geometry("400x700") # ×ではなく、アルファベットのx
root.resizable(0,0) # 00で上下リサイズできなくなる
root.config(bg = "white") # バックグラウンドカラーを変更する

input_frame = tkinter.LabelFrame(root)
input_frame.config(text = "This is entry")
input_frame.config(width = 350, height = 350)
input_frame.pack(padx = 10, pady = 10)

output_frame = tkinter.LabelFrame(root)
output_frame.config(text = "This is output")
output_frame.config(width = 350, height = 350)
output_frame.pack(padx = 10, pady = 10)

# ラジオボタンの設定
number = IntVar()
# number はラジオボタンの番号に相当する(何番が押されたかの情報を格納)

radio_1 = tkinter.Radiobutton(input_frame,variable = number,value = 1)
radio_1.config(text = "Number one")
radio_2 = tkinter.Radiobutton(input_frame,variable = number,value = 2)
radio_2.config(text = "Number two")
radio_3 = tkinter.Radiobutton(input_frame,variable = number,value = 3)
radio_3.config(text = "Number three")
print_button = tkinter.Button(input_frame)
print_button.config(text = "Button")
print_button.config(command = make_label)
# ラジオボタンの配置

radio_1.grid(row = 0, column = 0, padx = 10, pady = 10)
radio_2.grid(row = 0, column = 1, padx = 10, pady = 10)
radio_3.grid(row = 0, column = 2, padx = 10, pady = 10)
print_button.grid(row = 1, column = 0, padx = 10, pady = 10)

# アウトプット


# rootの実行
root.mainloop()

画像を出力する

次は画像を出力してみます。

写真をアップする というよりは、ボタンをテキストで表すのではなく、特徴的なマークにしたり、画像を入れることによって、見た目をよくすることができます。

後は、画像をアプリに入れて、画像処理を施した結果を出力してみたり、アプリそのものに活用することも可能でしょう。

Tkinterで画像を表示場合、デフォルトではpngしか出力することができません。

jpegはダメだということです。

ここではjpegも入れたいだろうということで、Pillowを使います。

もしPillowがお使いの環境になければインストールします。

pip install Pillow


少しわかりにくいですが、上から「png画像」「ボタン」「jpeg画像」となっています。

jpeg画像を入れるためには一度、「Image.open(〇〇.jpeg)」で画像を読み込む必要があります。

# tkinter_basic_07.py
# ラジオボタンの作成

import tkinter 


# ウィンドウの定義
root = tkinter.Tk()
root.title("Image Basic")
root.iconbitmap("favicon.ico")
root.geometry("400x700")
root.config(bg = "white")

# 画像の読み込み
# jpegは不可なので注意
my_image = tkinter.PhotoImage(file= "button_test_image.png")
my_label = tkinter.Label(root, image = my_image)
my_label.pack()

# ボタンに画像を載せることも出来る
my_button = tkinter.Button(root,image = my_image)
my_button.pack()

### jpgを読み込みたいときは…
from PIL import ImageTk, Image

my_label = tkinter.Label(root, image = my_image)
jpeg_image = ImageTk.PhotoImage(Image.open("button_test_image.png"))
jpeg_label = tkinter.Label(root, image = jpeg_image)
jpeg_label.pack()


# rootの実行
root.mainloop()

まとめ

今回の記事では、Tkinterの基本であるフレームと、入力フォーム、ボタン、そして画像について扱いました。

前回の記事で扱った、ラベルと組み合わせることで、入力を受け付けて結果をラベル出力するというシンプルなアプリが作れるようになります。

次回は画像などを扱って、出来る幅を広げていきます。