tkinterで最初のウィンドウを表示する(Hello World)
Pythonの標準ライブラリ tkinter で、画面にウィンドウを1枚出すところから始めます。コードのどの行が画面のどこになるのか、そしてウィンドウが出ないときにどこを見ればいいのかまで通しで解説します。
コードだけ欲しい方は「4. 完全なソースコード」へ。ウィンドウが出ない・一瞬で消えるという状態の方は「ウィンドウが表示されない・一瞬で消える」へ、No module named 'tkinter' と出る方は「3. tkinterが使えるか30秒で確認する」の対処表へ進んでください。
1. このページで作るもの
Pythonの文法を少し覚えたあと、多くの人が最初に「作った感」を得られるのがGUIアプリです。ここでは標準ライブラリの tkinter を使って、ボタンを押すと文字が変わる小さなウィンドウを1枚作ります。
実際に完成する画面が次の3枚です。図1が起動直後、図2が「クリックしてね!」を押したあとの状態です。3枚目は同じコードを Linux Mint 22.3 で実行した画面です。
読み終わったとき、あなたは次の3つができるようになります。①自分のPCでウィンドウを表示できる、②コードのどの行が画面のどこに効いているか説明できる、③ウィンドウが出ないときに原因を自分で切り分けられる。特に大事なのは3つ目です。ここでつまずいて「GUIは難しい」と諦めてしまう人が、とても多いからです。
このページで扱う機能
- ウィンドウの表示とタイトル・サイズの設定
- Labelウィジェットでのテキスト表示
- Buttonウィジェットとクリック時の処理
- マウスが乗ったときに色を変えるイベント処理
- フォント・文字色・背景色のカスタマイズ
図1・図2 は Windows 11 で撮影し、並べた3枚目は Linux Mint 22.3(仮想マシン)で撮影しました。掲載しているコードは Windows 11 / Python 3.12.10 の環境で構文を検証し、Tcl/Tk のバージョンは tkinter.TkVersion・tkinter.TclVersion で確認しました(いずれも 8.6)。Linux Mint 22.3(仮想マシン)でも起動と画面表示を確認しました。操作しての検証と実測は Windows 11 のみです。macOS は未検証です。仕様の説明はPython公式ドキュメントの tkinter のページで裏取りし、引用箇所には出典を添えています。
2. tkinterとGUIの3層構造
公式ドキュメントは tkinter を「Tcl/Tk GUI ツールキットに対する標準の Python インターフェース」と説明しています。Tk という別の言語(Tcl)で作られたGUIの部品セットを、Pythonから呼び出すための窓口が tkinter です。
GUIのコードは一見ごちゃごちゃして見えますが、構造は3層しかありません。この3層さえ頭に入れば、以降のアプリはすべて同じ形の繰り返しになります。
第1層: ウィンドウを作る
root = tk.Tk() の1行が土台です。公式ドキュメントはこの行について「Tkを初期化して関連するTclインタプリタを作成し、ルートウィンドウと呼ばれるトップレベルウィンドウを生成する。これがアプリケーションのメインウィンドウになる」と説明しています。以降に作る部品はすべて、このルートウィンドウの中に置かれます。
第2層: ウィジェットを作って配置する
ボタンや文字などの部品を、GUIでは「ウィジェット」と呼びます。ここが最初の落とし穴です。公式ドキュメントははっきりこう書いています。
「ウィジェットを作っただけでは表示されません。ウィジェットはジオメトリマネージャに渡されて初めて現れます。ジオメトリマネージャの呼び出し忘れは、初期によくある間違いです。ウィジェットは作られているのに、何も表示されません」(Python公式ドキュメント tkinter より翻訳。原文は英語版・2026年8月16日確認)
つまり tk.Label(...) と書いただけでは何も出ません。pack()・grid()・place() のどれかを呼んで初めて画面に現れます。「ウィンドウは出るのに文字が出ない」という質問の大半はこれです。
第3層: イベントループを回す
最後の root.mainloop() でイベントループに入ります。公式の説明は「Tkイベントループに入り、すべてのウィンドウが破棄されるまでイベントを処理する。通常はアプリケーションを実行するためにルートウィンドウで1回だけ呼ぶ」です。この行がないと、プログラムはウィンドウを作った直後に終了してしまいます。
tk と ttk、どちらで書くべきか
tkinterには昔からのウィジェット(tk.Label など)と、Tk 8.5で追加されたテーマ対応ウィジェット(ttk.Label など)の2系統があります。公式ドキュメントは、ttkのウィジェットについて「OSのネイティブなテーマに見た目を合わせるため、見た目が固定のクラシックなウィジェットより一貫した外観になる」(Python公式ドキュメント tkinter.ttk・2026年8月16日確認)と述べる一方、こんな注意書きも添えています。
「新旧どちらのAPIも利用できます。ネット上で見つかるドキュメントの多くは今も古いAPIを使っており、ひどく古い内容のこともあります」(Python公式ドキュメント tkinter より翻訳。原文は英語版・2026年8月16日確認)
それを承知のうえで、このページはクラシックな tk のウィジェットを使います。理由は色です。ttkのウィジェットは公式ドキュメントいわく「fg・bg など見た目に関するオプションは存在しない」(Python公式ドキュメント tkinter.ttk・2026年8月16日確認)ため、色を変えるには ttk.Style を別に定義する必要があります。最初の1本で「fg="red" と書いたら赤くなった」という手応えを優先しました。見た目をOS標準に寄せたくなったら、tk.Label を ttk.Label に置き換えてスタイルを学ぶ、という順番で構いません。
3. tkinterが使えるか30秒で確認する
tkinterは標準ライブラリなので pip install は不要です。ただし公式ドキュメントでは「オプションのモジュール」と位置づけられており、Pythonの配布元によっては入っていないことがあります。書き始める前に、使える状態かどうかを先に確かめておくと迷子になりません。
確認その1: python -m tkinter を実行する
公式ドキュメントが案内している一番確実な方法です。「コマンドラインから python -m tkinter を実行すると簡素な Tk インターフェースを表示するウィンドウが開き、システムに tkinter が正しくインストールされたことが分かります。さらに、インストールされた Tcl/Tk のバージョンが表示されます」と書かれています。
python -m tkinter
小さなウィンドウが開けば準備完了です。Windowsで python が反応しない場合は py -m tkinter も試してください。ウィンドウは右上の ✕ で閉じて構いません。
確認その2: バージョンを表示する
ウィンドウを開かずに確認したいときは、次の1行で済みます。筆者の環境(Windows 11 / Python 3.12.10)では 8.6 8.6 と表示されました。
python -c "import tkinter; print(tkinter.TkVersion, tkinter.TclVersion)"
公式ドキュメントによると、tkinterがサポートする最低バージョンは Tcl/Tk 8.5.12 で、python.org が配布する公式のバイナリには Tcl/Tk 8.6 が同梱されています。8.6 と表示されれば、このページのコードはそのまま動く想定です。
入っていなかったときの対処
ModuleNotFoundError: No module named 'tkinter' と出た場合、原因はPythonそのものではなく「Tcl/Tkが一緒に入らなかった」ことです。入れ方は配布元ごとに違います。
| 環境 | 状況 | 対処 |
|---|---|---|
| Windows(python.org版) | インストール時にTcl/Tkの機能を外すと入らない | 公式ドキュメントのオプション機能一覧では Include_tcltk(Tcl/Tk サポートと IDLE をインストールする)は既定で有効。外していた場合はインストーラーを再実行し、Modify から機能を追加する |
| macOS(python.org版) | 通常は同梱されている | まず python3 -m tkinter で確認する |
| macOS(Homebrew版) | Python本体と別のパッケージになっている | Homebrewには python-tk@3.12(Python interface to Tcl/Tk)などバージョン別のformulaがあり、brew install python-tk@3.12 のように使うPythonに合わせて入れる |
| Ubuntu / Debian | Python本体と別パッケージ | sudo apt install python3-tk(Debianの公式パッケージ説明は「Tkinter - Writing Tk applications with Python 3.x」) |
| Fedora系 | 同上 | ディストリビューションのパッケージ名は配布元の案内を確認する(公式ドキュメントも「配布元のドキュメントを見るように」と案内) |
検索するとまれに「pip install tkinter で入る」という説明が見つかりますが、tkinterはPython本体に付属するTcl/Tkへの窓口であって、PyPIから入れる普通のパッケージではありません。公式ドキュメントは、tkinterが見つからない場合は配布元(そのPythonを提供した相手)のドキュメントを見るように案内しています。上の表のとおり、Python本体の入れ直しかOS側のパッケージ追加で解決します。似た名前の無関係なパッケージを入れてしまう事故を避けるためにも、pipでの解決は試さないでください。
Pythonそのものがまだ入っていない場合は、先にPythonのインストール手順を済ませてください。エディタの準備がまだならVSCodeのセットアップもあわせてどうぞ。
出典: Python公式ドキュメント tkinter/同 Windowsでの使用(インストーラーのオプション機能)/Debian パッケージ python3-tk/Homebrew formula python-tk@3.12(いずれも2026年8月16日確認)
4. 完全なソースコード
右上の「コピー」ボタンをクリックするとコードをクリップボードにコピーできます。
全体で100行ほど(空行とコメントを除くと約70行)です。まずはそのままコピーして app001.py という名前で保存し、動く画面を見てしまうのが近道です。1行ずつの意味は次の章で分解します。日本語のフォント名を指定しているので、環境によって文字の見え方は多少変わります。
import tkinter as tk
from tkinter import font as tkfont
def on_button_click():
"""ボタンがクリックされたときの処理"""
current = label_message.cget("text")
if current == "Hello, World!":
label_message.config(
text="Pythonの学習を始めよう!",
fg="#e74c3c"
)
else:
label_message.config(
text="Hello, World!",
fg="#2c3e50"
)
def on_hover_enter(event):
"""マウスオーバー時にボタンの色を変える"""
btn_greet.config(bg="#2980b9")
def on_hover_leave(event):
"""マウスが離れたときにボタンの色を元に戻す"""
btn_greet.config(bg="#3498db")
# ============================================================
# ウィンドウの作成
# ============================================================
root = tk.Tk()
root.title("Hello World - Python GUI入門")
root.geometry("420x280")
root.resizable(False, False) # サイズ変更を禁止
root.configure(bg="#ecf0f1") # 背景色
# ============================================================
# フォント定義
# ============================================================
font_title = tkfont.Font(family="Noto Sans JP", size=20, weight="bold")
font_btn = tkfont.Font(family="Noto Sans JP", size=11, weight="bold")
# ============================================================
# ウィジェットの配置
# ============================================================
# タイトルラベル
label_title = tk.Label(
root,
text="🐍 Python GUI 入門",
font=font_title,
bg="#3498db",
fg="white",
pady=12
)
label_title.pack(fill=tk.X)
# メッセージラベル
label_message = tk.Label(
root,
text="Hello, World!",
font=("Noto Sans JP", 24, "bold"),
bg="#ecf0f1",
fg="#2c3e50",
pady=30
)
label_message.pack()
# ボタン
btn_greet = tk.Button(
root,
text="クリックしてね!",
font=font_btn,
bg="#3498db",
fg="white",
activebackground="#2980b9",
activeforeground="white",
relief=tk.FLAT,
padx=20,
pady=8,
cursor="hand2", # カーソルを手の形に
command=on_button_click
)
btn_greet.pack()
# ホバーイベントをバインド
btn_greet.bind("<Enter>", on_hover_enter)
btn_greet.bind("<Leave>", on_hover_leave)
# 説明ラベル
label_hint = tk.Label(
root,
text="ボタンをクリックするとメッセージが変わります",
font=("Noto Sans JP", 9),
bg="#ecf0f1",
fg="#7f8c8d"
)
label_hint.pack(pady=(8, 0))
# ============================================================
# イベントループ開始(これを忘れるとウィンドウが表示されない)
# ============================================================
root.mainloop()
5. コード解説(1行ずつ)
まず全体像です。次の図は、コードのどの行が画面のどの部分になるのかを番号で対応させたものです。細かい構文の前に、この対応関係を眺めておくと迷いにくくなります。
ここから順番に見ていきます。変数や関数の書き方そのものに不安があれば、Pythonの基本構文と関数の使い方もあわせて確認してください。
5-1. import: tkinterを呼び出す
import tkinter as tk
from tkinter import font as tkfont
as tk と別名を付けるのは、以降 tk.Tk()・tk.Label() のように短く書けるようにするためです。tkinterのコードはほぼこの書き方で流通しているので、真似しておくとサンプルを読むときに楽になります。2行目の tkinter.font は、フォントを名前・サイズ・太さで組み立てるためのサブモジュールです。
5-2. tk.Tk(): ウィンドウ本体を作る
root = tk.Tk()
root.title("Hello World - Python GUI入門")
root.geometry("420x280")
root.resizable(False, False) # サイズ変更を禁止
root.configure(bg="#ecf0f1") # 背景色
tk.Tk() が第1層のルートウィンドウです。続く4行は、タイトルバー・大きさ・リサイズ可否・背景色の設定です。公式ドキュメントでは、タイトルや位置・大きさ・アイコンといった「ウィンドウの外枠」の操作は、ウィンドウマネージャ経由のメソッドとしてまとめられています。title() は wm_title() と同じものです。
"420x280" の区切りは小文字のエックスです。「×」(かける記号)ではありません。また数値ではなく文字列で渡します。root.geometry(420, 280) のように書くとエラーになります。位置だけ指定したいときは "+100+50"、両方なら "420x280+100+50" の形です。
5-3. tk.Label(): 文字を表示する
label_message = tk.Label(
root, # 第1引数は親ウィジェット
text="Hello, World!",
font=("Noto Sans JP", 24, "bold"), # (フォント名, サイズ, スタイル)
bg="#ecf0f1", # background の短縮形
fg="#2c3e50", # foreground(文字色)の短縮形
pady=30 # 上下の余白
)
label_message.pack()
第1引数の root は「どこに属する部品か」を示す親の指定です。fg・bg は foreground・background の短縮形で、色は "#RRGGBB" 形式でも "red" のような色名でも指定できます。フォントは ("フォント名", サイズ, "bold") のタプルで渡すのが手軽です。
5-4. pack / grid / place: 配置しないと出てこない
作ったウィジェットは、ジオメトリマネージャに渡して初めて表示されます。3種類あり、公式ドキュメントの説明は次のとおりです。
| メソッド | 並べ方 | 向いている場面 |
|---|---|---|
pack() | コンテナの上下左右いずれかの辺に向かって積んでいく | 今回のように縦一列に並べるだけの画面 |
grid() | 行と列の表形式に並べる | 入力フォームや電卓のボタン配置。公式は「もっとも柔軟で、既定で選ぶべきマネージャ」と説明 |
place() | 座標や比率で位置を明示的に指定する | 重ね合わせなど、他の2つで表現しにくい配置 |
今回は縦に4つ並べるだけなので pack() を使いました。label_title.pack(fill=tk.X) の fill=tk.X は「横方向いっぱいに広げる」指定で、これがあるためタイトルの青い帯が画面の左端から右端まで伸びています。表形式に並べたいときは次のように grid() を使います。
import tkinter as tk
root = tk.Tk()
tk.Label(root, text="名前").grid(row=0, column=0, padx=8, pady=4)
tk.Entry(root).grid(row=0, column=1, padx=8, pady=4)
tk.Label(root, text="メール").grid(row=1, column=0, padx=8, pady=4)
tk.Entry(root).grid(row=1, column=1, padx=8, pady=4)
root.mainloop()
公式ドキュメントは「同じコンテナを共有する2つのウィジェットに pack() と grid() を適用してはいけない。両者はサイズの調整方法が相容れず、互いにコンテナのサイズを変え合ってアプリが固まることがある」と警告しています。混在させたいときは、tk.Frame で入れ物を分けてから、フレームごとに別のマネージャを使ってください。エラーメッセージが出ないまま画面が固まるため、原因に気づきにくい部類のトラブルです。
5-5. tk.Button(): クリックで関数を呼ぶ
btn_greet = tk.Button(
root,
text="クリックしてね!",
# 色やフォントの指定は4章のコードを参照
cursor="hand2", # カーソルを手の形に
command=on_button_click # ← カッコを付けない
)
btn_greet.pack()
ここが最初の関門です。command に渡すのは「実行結果」ではなく「関数そのもの」です。公式ドキュメントも、コールバックとして渡すのは引数を取らないPythonの関数だと説明しています。
| 書き方 | 何が起きるか |
|---|---|
command=on_button_click | 正しい。クリックされたときに関数が呼ばれる |
command=on_button_click() | その場で関数が実行され、戻り値(多くは None)が登録される。結果としてボタンを押しても何も起きない |
「押してもいないのに動いた」「押しても反応しない」はほぼこの1文字違いです。引数を渡したいときは lambda で包みます。
def show(message):
label_message.config(text=message)
tk.Button(root, text="おはよう", command=lambda: show("おはよう!")).pack()
tk.Button(root, text="またね", command=lambda: show("またね!")).pack()
5-6. cget と config: 表示を後から変える
def on_button_click():
current = label_message.cget("text") # 今の文字を読む
if current == "Hello, World!":
label_message.config(text="Pythonの学習を始めよう!", fg="#e74c3c")
else:
label_message.config(text="Hello, World!", fg="#2c3e50")
cget("text") は現在の設定値を読み出すメソッドで、公式ドキュメントによれば label_message["text"] と書いても同じです。config()(configure() の短縮形)は逆に設定を書き換えるメソッドで、複数のオプションをまとめて指定できます。
「今の状態を読む → 次の状態を決める → 書き換える」というこの流れは、GUIアプリでずっと使い回せる型です。文字を変える、色を変える、ボタンを押せなくする、いずれも同じ形で書けます。
5-7. bind(): マウスやキーの動きに反応する
def on_hover_enter(event):
btn_greet.config(bg="#2980b9")
def on_hover_leave(event):
btn_greet.config(bg="#3498db")
btn_greet.bind("<Enter>", on_hover_enter)
btn_greet.bind("<Leave>", on_hover_leave)
command がボタン専用の仕組みなのに対し、bind() はどのウィジェットでも使える汎用の仕掛けです。公式ドキュメントの説明では、<修飾キー-種類-詳細> という形式の文字列でイベントを指定し、イベントが起きるとイベント情報を持つオブジェクトが引数として1つ渡されるとされています。on_hover_enter(event) の event がそれです。使わなくても、受け取る引数は書いておく必要があります。
<Enter> はマウスがウィジェットに乗ったとき、<Leave> は離れたときです。名前からEnterキーを連想しがちですが、キーボードのEnterは <Return> なので混同しないよう注意してください。
5-8. mainloop(): ここで初めて画面が出る
root.mainloop()
公式ドキュメントの説明は「Tkイベントループに入り、すべてのウィンドウが破棄されるまでイベントを処理する。通常はアプリケーションを実行するためにルートウィンドウで1回だけ呼ぶ」です。プログラムはこの行で止まり、クリックやキー入力を待ち続けます。✕ を押してウィンドウが閉じられると、ようやくこの行の次に進みます。
言い換えると、ここまでの行はすべて「準備」で、画面が現れるのはこの1行のおかげです。ファイルの末尾に置くのを忘れないでください。
出典: Python公式ドキュメント tkinter(2026年8月16日確認)
6. 3行から作る7ステップ
完成コードをいきなり写経すると、どこで失敗したのか分からなくなります。3行の空っぽのウィンドウから始めて、1ステップごとに実行して確認するのがおすすめです。壊れた瞬間が分かるので、原因の切り分けが一気に楽になります。
-
1ファイルを作成する
エディタで新しいファイルを作り、
app001.pyという名前で保存します。保存先は日本語やスペースを含まないフォルダにしておくと、後々のトラブルが減ります。 -
2まず3行で空のウィンドウを出す
この3行だけで、灰色の空っぽのウィンドウが表示されます。ここが動かない場合は環境側の問題なので、3章に戻ってください。
import tkinter as tk root = tk.Tk() root.mainloop() -
3タイトルとサイズを付ける
root = tk.Tk()とroot.mainloop()の間に書き足します。以降のステップもすべてこの間に追加していきます。root.title("Hello World") root.geometry("400x250") -
4ラベルを置いて文字を出す
2行セットで書きます。1行目が作成、2行目が配置です。ためしに
label.pack()の行だけコメントアウトして実行すると、「作っても配置しないと出ない」ことを体感できます。label = tk.Label(root, text="Hello, World!", font=("Arial", 20)) label.pack(pady=30) -
5ボタンを置いて反応を見る
まずは押したらターミナルに文字が出るだけの、いちばん簡単な形で確認します。画面ではなくターミナル側に
clicked!が出れば、クリックが関数に届いています。btn = tk.Button(root, text="クリック", command=lambda: print("clicked!")) btn.pack() -
6ボタンで画面の文字を変える
ターミナルへの出力を、ラベルの書き換えに置き換えます。ここまで来れば「操作に反応して画面が変わるアプリ」の骨格は完成です。
def on_click(): label.config(text="ボタンが押されました!", fg="#e74c3c") btn = tk.Button(root, text="クリック", command=on_click) btn.pack() -
7実行して確認する
ターミナルで
python app001.pyを実行します(Windowsでpythonが反応しないときはpy app001.py)。VSCodeなら右上の実行ボタンでも構いません。あとは4章の完成コードと見比べて、フォントや色の指定を足していけば同じ画面になります。
VSCodeで実行ボタンが出ない・Pythonが選べないといった場合は、VSCodeのPython環境セットアップで拡張機能とインタープリターの設定を確認してください。
7. 自分でいじって試す5つの実験
写経が終わったら、次は意図的に書き換えて結果を見る番です。1か所ずつ変えて実行するだけで、「この行が画面のここに効いている」という感覚が短時間で身につきます。所要時間はどれも数分です。
実験1: 文字の色と大きさを変える(1行)
label_message の fg と font を書き換えるだけです。色は "#0066cc" のような16進数でも "red" のような色名でも指定できます。
label_message.config(fg="#0066cc", font=("Noto Sans JP", 32, "bold"))
数字を極端に大きくすると、文字がウィンドウからはみ出します。geometry() の値との関係が見えてくるはずです。
実験2: ボタンを増やして、押した文字を出し分ける
ボタンが2つ以上になると、関数に引数を渡したくなります。lambda で包む書き方をここで覚えてしまいましょう。
def show(message):
label_message.config(text=message)
tk.Button(root, text="おはよう", command=lambda: show("おはよう!")).pack()
tk.Button(root, text="またね", command=lambda: show("またね!")).pack()
ここまで書ければ、あとはボタンの数を増やすだけでクイズや電卓の形に近づきます。
実験3: クリック回数を数える
関数の外にある変数を書き換えるには global が要ります。「押すたびに状態が変わる」アプリの最小形です。
count = 0
def on_click():
global count
count += 1
label_message.config(text=f"クリック回数: {count}")
global を書き忘れると UnboundLocalError になります。この書き方が窮屈に感じてきたら、クラスにまとめる書き方(8章の最後)に進む合図です。
実験4: ウィンドウを画面の中央に出す
起動時の位置は自分で計算して指定できます。update_idletasks() で現在のサイズを確定させてから、画面サイズとの差の半分を座標にします。
root.update_idletasks()
w = root.winfo_width()
h = root.winfo_height()
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
x = (sw - w) // 2
y = (sh - h) // 2
root.geometry(f"+{x}+{y}")
この8行を関数にしておくと、以降のアプリすべてで使い回せます。自作の道具が1つ増えた状態です。
実験5: タイトルバーのアイコンを差し替える
アイコン画像を用意して指定します。Windowsは ICO 形式、macOS/Linux は PhotoImage 経由の指定が一般的です。画像ファイルは app001.py と同じフォルダに置いてください。
# Windows
root.iconbitmap("icon.ico")
# macOS / Linux
icon = tk.PhotoImage(file="icon.png")
root.iconphoto(True, icon)
ファイルが見つからないと TclError になります。パスの書き方は環境によって差が出やすい部分なので、うまくいかないときは絶対パスで試して切り分けてください。
8. うまく動かないときの症状別チェック
GUIは「エラーが出ないのに思ったとおりにならない」ことがあります。まず症状から当たりを付けてください。
| 症状 | まず疑うところ |
|---|---|
| ウィンドウが出ない・一瞬で消える | root.mainloop() の書き忘れ |
| ウィンドウは出るが中身が空 | pack() / grid() の呼び忘れ |
No module named 'tkinter' | Tcl/Tkが入っていない(3章) |
| 押していないのに関数が動いた/押しても無反応 | command=関数() のカッコ |
| 文字が □ や ? になる | フォント指定と日本語対応 |
| 操作を受け付けず固まる | time.sleep() の使用、または pack() と grid() の混在 |
| 赤いエラーメッセージが出る | 末尾の行から読む(エラー一覧&解決法) |
❌ ウィンドウが表示されない・一瞬で消える
原因: root.mainloop() がない、または if やインデントの内側に入っていて実行されていません。公式ドキュメントのとおり、mainloopは「すべてのウィンドウが破棄されるまでイベントを処理する」ための行で、これがないとプログラムは最後まで進んで即終了します。
対処: ファイルの一番下に、インデントなしで root.mainloop() があるか確認してください。ウィジェットを追加する行は、必ずこの行より上に書きます。
❌ ウィンドウは出るのに、ラベルやボタンが見えない
原因: ウィジェットを作っただけで配置していません。公式ドキュメントが「初期によくある間違い」と名指ししている状態です。
対処: 作成した各ウィジェットに pack()・grid()・place() のいずれかを呼んでください。なお label = tk.Label(...).pack() と1行にまとめると、label には None が入ります(pack() の戻り値)。あとから label.config(...) したい場合は、作成と配置を2行に分けてください。
# あとで書き換えたいウィジェットは2行に分ける
label = tk.Label(root, text="Hello, World!")
label.pack()
❌ ModuleNotFoundError: No module named 'tkinter'
原因: Pythonは入っているものの、Tcl/Tkの部分が一緒に入っていません。pip install tkinter では解決しません。
対処: 3章の対処表のとおりに対応します。WindowsはインストーラーでTcl/Tkの機能を有効にして入れ直し、Ubuntu/Debianは sudo apt install python3-tk で追加します。Homebrew版のPythonは、対応する python-tk のformulaを入れてください。他のエラーメッセージも含めた逆引きはPythonエラー一覧のModuleNotFoundErrorの章にまとめています。
❌ ボタンを押していないのに関数が動く/押しても無反応
原因: command=on_button_click() のようにカッコを付けています。これは「関数を今すぐ実行して、その戻り値を command に渡す」という意味になります。
対処: カッコを外して command=on_button_click と書きます。引数を渡したいときは command=lambda: show("こんにちは") の形にしてください。
❌ 日本語が □ になる・意図した書体にならない
原因: 指定したフォント名がその環境に存在しません。存在しない名前を指定しても多くの場合エラーにはならず、別の書体で表示されます。
対処: OSに合わせて候補を変えます。Windowsなら "Yu Gothic UI" や "Meiryo"、macOSなら "Hiragino Sans" が定番です。実際に使える名前は次のコードで一覧できます。
import tkinter as tk
from tkinter import font as tkfont
root = tk.Tk()
root.withdraw() # ウィンドウは表示しない
print(sorted(tkfont.families())[:20]) # 先頭20件だけ表示
root.destroy()
なお、このページに掲載しているキャプチャ(Windows 11)では、コード中の絵文字がカラーではなく単色の記号のように描画されています。絵文字の見え方は環境とフォントに強く依存するので、確実に伝えたい情報は絵文字に頼らないほうが安全です。
❌ 実行中にウィンドウが固まる・「応答なし」になる
原因: time.sleep() や重い処理をイベントループの中で実行しています。mainloopが自分の処理で塞がると、その間クリックや再描画を処理できません。
対処: 「一定時間後に実行したい」だけなら after() を使います。指定ミリ秒後に関数を1回呼ぶ仕組みで、ループを止めません。時計やタイマーはこの形で作ります。
import time
def tick():
label_message.config(text=time.strftime("%H:%M:%S"))
root.after(1000, tick) # 1000ミリ秒後にもう一度自分を呼ぶ
tick()
root.mainloop()
スレッドから画面を操作した場合の RuntimeError: main thread is not in main loop については、エラー解決ページのRuntimeErrorの章で扱っています。
❌ NameError: name 'label' is not defined
原因: 関数の中から、まだ作られていない(または別のスコープにある)ウィジェットを参照しています。関数の定義がウィジェットの作成より前にあっても、呼ばれるのは実行時なので通常は問題ありません。定義そのものが抜けていないか、名前のつづりを間違えていないかを疑ってください。
対処: グローバル変数が増えて見通しが悪くなってきたら、クラスにまとめる書き方に移行すると一気に整理できます。ウィジェットを self. で持たせるだけで、スコープの悩みはほぼ消えます。
import tkinter as tk
class HelloApp:
def __init__(self, master):
self.label = tk.Label(master, text="Hello, World!", font=("Arial", 20))
self.label.pack(pady=20)
tk.Button(master, text="変える", command=self.change).pack()
def change(self):
self.label.config(text="Pythonの学習を始めよう!")
root = tk.Tk()
app = HelloApp(root)
root.mainloop()
出典: Python公式ドキュメント tkinter(2026年8月16日確認)
9. 練習問題
手を動かして初めて身につきます。ヒントだけ添えるので、答えを見る前に自分の手で書いてみてください。
-
課題1: ボタンを3つ並べる
「こんにちは」「さようなら」「ありがとう」の3つのボタンを作り、押したボタンに応じてラベルの文字を変えましょう。
ヒント: 関数を3つ書いてもできますが、lambdaで引数を渡す形にすると関数1つで済みます(実験2の形)。 -
課題2: クリックカウンター
クリック回数を数えて表示し、10回ごとに「よく押しますね!」などメッセージが変わるようにしましょう。
ヒント: 10回ごとの判定はcount % 10 == 0です。 -
課題3: カラーチェンジャー
ボタンを押すたびにウィンドウの背景色がランダムに変わるアプリを作りましょう。
ヒント:random.randint(0, 255)を3回使い、f"#{r:02x}{g:02x}{b:02x}"の形にすると16進数の色コードになります。背景色の変更はroot.configure(bg=色)です。 -
課題4: 閉じるボタンを付ける
「終了」ボタンを追加し、押したらウィンドウが閉じるようにしましょう。
ヒント: ウィンドウを破棄するメソッドはroot.destroyです。commandにはカッコを付けずに渡します。
10. よくある質問
Q. tkinterを使うのに別途インストールは必要ですか?
ほとんどの場合は不要です。tkinterは標準ライブラリで、python.org が配布するWindows版・macOS版にはTcl/Tkが同梱されています。ただし公式ドキュメント上は「オプションのモジュール」扱いで、Linuxのディストリビューションやパッケージマネージャ経由のPythonでは別パッケージになっていることがあります。判断は python -m tkinter の結果で付けてください。
Q. pip install tkinter が失敗します。
tkinterはPyPIから入れるパッケージではないので、その方法では解決しません。Python本体の構成(Windowsはインストーラーの「tcl/tk and IDLE」)か、OS側のパッケージ(Debian/Ubuntuなら python3-tk)として追加します。詳しくは3章にまとめました。
Q. tk と ttk はどちらで書き始めるべきですか?
最初の数本はクラシックな tk で構いません。fg・bg で直接色を変えられるため、コードと画面の対応が分かりやすいからです。見た目をOS標準に近づけたくなったら ttk に移行します。その際、色の指定は ttk.Style 経由に変わる点だけ注意してください。公式ドキュメントも「新旧どちらのAPIも利用できる」と明記しています。
Q. macOSやLinuxでも同じコードが動きますか?
公式ドキュメントによれば、TkとtkinterはmacOSを含むほとんどのUnixプラットフォームとWindowsで利用できます。コードはそのまま動く想定ですが、フォント名・ボタンの見た目・ウィンドウの余白は環境によって変わります。当サイトでは Windows 11 と Linux Mint 22.3 で起動を確認しました(1章の3枚目が Linux Mint の画面です)。macOS は未検証です。
Q. 作ったアプリを他の人に配れますか?
Pythonが入っていない相手に渡すには、実行ファイルにまとめるツールが別途必要です。ただしツールの選定と設定は初心者がつまずきやすい領域なので、まずは自分の環境で動くアプリを何本か作ってからで十分です。このページの範囲では扱いません。
Q. tkinterの次はどのGUIライブラリを学ぶべきですか?
いきなり乗り換える必要はありません。tkinterで「作る・配置する・イベントで動かす」の3層に慣れておくと、他のライブラリでも同じ考え方が通用します。どんな選択肢があるかはPythonライブラリ一覧のGUI関連の項目を参照してください。
Q. コードは動いたけれど、意味が半分くらいしか分かりません。
それで正常です。GUIは「文法」と「ライブラリ固有の作法」が同時に来るので、初回で全部は入りません。基本構文と関数を復習しつつ、次のアプリで同じ形が出てきたときに「これは見たことがある」と思えれば十分に前進しています。
11. 次の一歩
ウィンドウが出せたら、次は同じ3層構造のまま、部品を増やす段階です。急に難しいものへ飛ばず、1本ごとに新しい要素を1つだけ足していくのが、結局いちばん速い進み方です。
| 次に作るもの | ここで新しく身につく要素 |
|---|---|
| シンプル電卓 | grid() によるボタンの表配置と、入力値の取り出し |
| デジタル時計 | after() による定期更新(画面を止めずに動かす) |
| ストップウォッチ | 開始・停止など「状態」を持つアプリの作り方 |
| ToDoリスト | 入力欄とリスト表示、データの追加と削除 |
まずはGridレイアウトを使うシンプル電卓がおすすめです。イベント処理を関数にまとめて整理できるようになると、この先のアプリ作りがぐっと楽になります。
独学の順番を1冊で固めたい場合は、Python学習本の比較で入門書の選び方をまとめています。手を動かす教材はこのサイトの初心者用GUIアプリ一覧から好きなものを選んでください。
写経中に赤いエラー文が出たら、Pythonエラー一覧&解決法(英語メッセージ逆引き)で原因と直し方をすぐ確認できます。
写経しながら「なぜこう書くのか」が気になり始めたら、入門書を1冊通して読むと断片的な知識がつながります。Python入門書のおすすめ2冊(当サイトの参考書ランキング総合1〜2位)で、独学者向けの最初の1冊を比較しています。