Python | 1 日 120 分 × 7 日アプリ学習:tkinterで作るGUIアプリ(中級編)

Web APP Python
スポンサーリンク

4日目のゴール

4日目のテーマは
「ボタンとGUI部品を“きれいに並べて”、アプリらしい画面を作る」 ことです。

ここまでであなたはすでに、

ウィンドウを出せる
ボタンを押して関数を呼べる
Entry から入力を受け取って、ラベルに表示できる

というところまで来ています。

4日目では一歩進んで、

部品を「縦に積むだけ」から卒業する
grid を使って、行と列でレイアウトする
ボタン・ラベル・Entry を“意味のある配置”にする

という、「見た目もちゃんとしたGUI」の入り口に入ります。


pack だけだと、だんだんつらくなる理由

縦に積むだけだと「フォーム」が作りにくい

3日目までのコードは、だいたいこうでした。

label_name.pack()
entry_name.pack()
label_like.pack()
entry_like.pack()
button.pack()
label_result.pack()
Python

これはこれでシンプルで良いのですが、
例えばこんな画面を作りたくなったらどうでしょう。

「名前: [ ]」
「年齢: [ ]」
「好きなもの: [ ]」

というように、
ラベルと入力欄を横に並べたい。

pack() だけでこれをやろうとすると、
急に難易度が上がります。

そこで登場するのが、
「行と列で部品を配置する grid です。


grid の基本を押さえる

行(row)と列(column)で考える

grid は、
「表(テーブル)」をイメージすると分かりやすいです。

1行目・0列目にラベル
1行目・1列目にEntry
2行目・0列目にラベル
2行目・1列目にEntry

というように、
「どの行・どの列に置くか」を指定していきます。

まずは、名前と年齢を入力する簡単なフォームを
grid で作ってみましょう。

import tkinter as tk

root = tk.Tk()
root.title("gridの基本")

label_name = tk.Label(root, text="名前:")
entry_name = tk.Entry(root)

label_age = tk.Label(root, text="年齢:")
entry_age = tk.Entry(root)

label_name.grid(row=0, column=0)
entry_name.grid(row=0, column=1)

label_age.grid(row=1, column=0)
entry_age.grid(row=1, column=1)

root.mainloop()
Python

ここでの重要ポイントは、

grid(row=行番号, column=列番号) で配置する
行と列は 0 から始まる(0行目、1行目…)

ということです。


pack と grid は「同じ親の中で混ぜない」

これをやるとエラーになる

ひとつだけ、かなり大事なルールがあります。

同じウィンドウ(同じ親)に対して、packgrid を混ぜて使ってはいけない。

例えば、これはダメです。

label_name = tk.Label(root, text="名前:")
label_name.pack()

entry_name = tk.Entry(root)
entry_name.grid(row=0, column=1)  # ← 同じ root に pack と grid を混ぜている
Python

こうすると、実行時にエラーが出ます。

対策はシンプルで、

「同じ親の中では、packgrid のどちらかに統一する」

と覚えておけばOKです。

後で出てくる Frame を使うと、
「この枠の中は grid」「この枠の中は pack」
といった使い分けもできますが、
4日目ではまず「混ぜない」というルールだけ意識しておきましょう。


grid で「フォーム+ボタン+結果表示」を作る

3日目の自己紹介アプリを grid 版にする

3日目で作った「自己紹介メッセージメーカー」を、
grid でレイアウトし直してみます。

import tkinter as tk

def on_make_message():
    name = entry_name.get().strip()
    like = entry_like.get().strip()

    if name == "" or like == "":
        label_result.config(text="名前と好きなものを両方入力してください。")
        return

    message = f"私は{name}です。{like}が好きです。"
    label_result.config(text=message)

root = tk.Tk()
root.title("自己紹介メッセージメーカー(grid版)")

label_name = tk.Label(root, text="名前:")
entry_name = tk.Entry(root)

label_like = tk.Label(root, text="好きなもの:")
entry_like = tk.Entry(root)

button = tk.Button(root, text="メッセージを作る", command=on_make_message)

label_result = tk.Label(root, text="ここにメッセージが表示されます")

label_name.grid(row=0, column=0, padx=5, pady=5, sticky="e")
entry_name.grid(row=0, column=1, padx=5, pady=5)

label_like.grid(row=1, column=0, padx=5, pady=5, sticky="e")
entry_like.grid(row=1, column=1, padx=5, pady=5)

button.grid(row=2, column=0, columnspan=2, pady=10)

label_result.grid(row=3, column=0, columnspan=2, pady=10)

root.mainloop()
Python

ここで新しく出てきたものを、丁寧に見ていきます。


grid のオプションを深掘りする

padding(余白)を付ける padx, pady

padxpady は、
「部品の周りの余白」を指定します。

padx=5 は左右に5ピクセルの余白
pady=5 は上下に5ピクセルの余白

です。

これを付けるだけで、
ぎゅうぎゅう詰めの画面から、
少し余裕のある見た目になります。


sticky で「どの方向にくっつけるか」を決める

sticky は、
「セル(マス)の中で、どの方向に寄せるか」を指定します。

sticky="e" は east(東)=右寄せ
sticky="w" は west(西)=左寄せ
sticky="n" は north(北)=上寄せ
sticky="s" は south(南)=下寄せ

複数組み合わせることもできます。

sticky="we" なら左右に広がる
sticky="ns" なら上下に広がる
sticky="nsew" なら四方向に広がる

今回のコードでは、

label_name.grid(..., sticky="e")
Python

として、
ラベルを「右寄せ」にしています。

これにより、

「名前: [ ]」
「好きなもの: [ ]」

のように、
ラベルが入力欄の右側にぴったり寄ってくれます。


columnspan で「列をまたぐ」

columnspan は、
「この部品を、何列分にまたがって表示するか」
を指定します。

button.grid(row=2, column=0, columnspan=2)
Python

これは、

「2行目の0列目から始めて、2列分を占有する」

という意味です。

今回のレイアウトでは、

0列目:ラベル
1列目:Entry

という構成なので、
ボタンや結果ラベルは「画面の横幅いっぱい」にしたくて
columnspan=2 にしています。


Frame で「まとまり」を作る

画面を“箱”で分けるイメージ

少しだけレベルを上げて、
Frame という部品を紹介します。

Frame は、
「他の部品を入れるための“箱”」
だと思ってください。

例えば、

上のエリア:入力フォーム
下のエリア:結果表示

というように、
画面をざっくり2つのエリアに分けたいときに使えます。


Frame を使った構成の例

import tkinter as tk

def on_make_message():
    name = entry_name.get().strip()
    like = entry_like.get().strip()

    if name == "" or like == "":
        label_result.config(text="名前と好きなものを両方入力してください。")
        return

    message = f"私は{name}です。{like}が好きです。"
    label_result.config(text=message)

root = tk.Tk()
root.title("Frameでエリア分け")

frame_form = tk.Frame(root)
frame_form.pack(padx=10, pady=10)

frame_result = tk.Frame(root)
frame_result.pack(padx=10, pady=10)

label_name = tk.Label(frame_form, text="名前:")
entry_name = tk.Entry(frame_form)

label_like = tk.Label(frame_form, text="好きなもの:")
entry_like = tk.Entry(frame_form)

button = tk.Button(frame_form, text="メッセージを作る", command=on_make_message)

label_result = tk.Label(frame_result, text="ここにメッセージが表示されます")

label_name.grid(row=0, column=0, padx=5, pady=5, sticky="e")
entry_name.grid(row=0, column=1, padx=5, pady=5)

label_like.grid(row=1, column=0, padx=5, pady=5, sticky="e")
entry_like.grid(row=1, column=1, padx=5, pady=5)

button.grid(row=2, column=0, columnspan=2, pady=10)

label_result.pack()

root.mainloop()
Python

ここでの構造を整理すると、

root の上に frame_formframe_resultpack で縦に並べる
frame_form の中では grid を使ってフォームを組む
frame_result の中では pack でラベルを置く

という形になっています。

大事なのは、

「親が違えば、packgrid を使い分けていい」

ということです。

同じ親の中で混ぜるのはNGですが、
Frame で親を分ければ、
レイアウトの自由度が一気に上がります。


4日目のミニアプリ:簡易ログイン画面(見た目だけ)

仕様

ユーザー名とパスワードを入力するフォーム
「ログイン」ボタン
結果を表示するラベル
レイアウトは grid で整える

中身の認証処理はまだやらず、
「見た目とボタンイベント」に集中します。


コード

import tkinter as tk

def on_login_click():
    username = entry_user.get().strip()
    password = entry_pass.get().strip()

    if username == "" or password == "":
        label_result.config(text="ユーザー名とパスワードを入力してください。")
        return

    label_result.config(text=f"{username} さんとしてログインを試みました。(ダミー)")

root = tk.Tk()
root.title("ログイン画面(ダミー)")

frame_form = tk.Frame(root)
frame_form.pack(padx=10, pady=10)

frame_result = tk.Frame(root)
frame_result.pack(padx=10, pady=10)

label_user = tk.Label(frame_form, text="ユーザー名:")
entry_user = tk.Entry(frame_form)

label_pass = tk.Label(frame_form, text="パスワード:")
entry_pass = tk.Entry(frame_form, show="*")

button_login = tk.Button(frame_form, text="ログイン", command=on_login_click)

label_user.grid(row=0, column=0, padx=5, pady=5, sticky="e")
entry_user.grid(row=0, column=1, padx=5, pady=5)

label_pass.grid(row=1, column=0, padx=5, pady=5, sticky="e")
entry_pass.grid(row=1, column=1, padx=5, pady=5)

button_login.grid(row=2, column=0, columnspan=2, pady=10)

label_result = tk.Label(frame_result, text="ここに結果が表示されます")
label_result.pack()

root.mainloop()
Python

ここで新しく出てきた show="*" は、
パスワード入力欄でよくある「●●●」表示をするためのものです。

Entry に show="*" を付けると、
入力した文字がそのまま見えず、
指定した文字(ここでは *)で表示されます。


4日目で絶対に押さえてほしい本質

「どこに何を置くか」を意識した瞬間、アプリは“それっぽく”なる

今日いちばん大事なのは、

GUIは「部品を並べる」だけでなく
「どこに何を置くか」を設計する世界

だという感覚です。

そのための道具が、

行と列で配置する grid
部品のまとまりを作る Frame
余白を付ける padx / pady
セルの中での位置を決める sticky
複数列にまたがる columnspan

といった要素たちです。

1〜3日目で学んだ

ボタンイベント
Entry からの入力
ラベルへの表示

に、今日の「レイアウトの基礎」を組み合わせると、
一気に「アプリっぽい画面」になります。

5日目以降は、
チェックボックス、ラジオボタン、リストボックスなどを足して、
「選択」「状態」「複数データ」を扱う方向に進んでいきます。

まずは今日のログイン画面を、自分なりに

ボタンを増やす(キャンセルボタンなど)
ラベルの位置や余白を変える
Frame を増やしてエリアを分ける

など、少しずついじって、
「レイアウトを自分でコントロールする感覚」を掴んでみてください。

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