ChatGPTでプログラミング学習ー02
tkinterを使ってみる
1.Hello, World!
前報でPythonのturtle graphicsの経験を報告しました.。今回はPythonのGUI(Graphic User Interface)についての体験学習です・
まずは、GUIのイメージつくりにサンプルプログラムをリクエストしてみました。
![](https://assets.st-note.com/img/1681197816188-ML5tISwSti.png?width=1200)
![](https://assets.st-note.com/img/1681197856056-CNyIXGPOQG.png?width=1200)
![](https://assets.st-note.com/img/1681198127510-Bw7zhaufKo.png)
windowの大きさを設定していないので、小さな可愛いHello,World!でした。文字はラベルの上に書くのですね。
2.ボタン、ラベル、テキストボックスの使用例
![](https://assets.st-note.com/img/1681202986223-aLIUCy6hQI.png?width=1200)
![](https://assets.st-note.com/img/1681203153303-NkycvlolLc.png?width=1200)
![](https://assets.st-note.com/img/1681203323644-Yv269TkWLh.png?width=1200)
text=textbox.get() -> label.config(text=text)->command=button_click
の一連の流れを覚えておきましょう。結果の図を下に示します。Windowの大きさを300x100とした場合です。
![](https://assets.st-note.com/img/1681205374745-u6OLgYNbJE.png)
![](https://assets.st-note.com/img/1681205374716-VmmglvkOuD.png)
こんな質問もしました。
![](https://assets.st-note.com/img/1681215425337-RwTLon2EYx.png?width=1200)
![](https://assets.st-note.com/img/1681215562611-NvCzq8IZRh.png?width=1200)
![](https://assets.st-note.com/img/1681217040475-9Ejl66JdW2.png)
結構使いこなすのは難しい気もしますね。
3.ジャンケン
前にpygameでジャンケンをやって、結構難しかった。今回、ボタンを使えば簡単そうだったので、再度チャレンジした。ジャンケンのルールはすでにtkinterは知っていました。
![](https://assets.st-note.com/img/1681353948370-pCXlZmSTw9.png?width=1200)
![](https://assets.st-note.com/img/1681354105939-vQ7LAeuZWV.png?width=1200)
![](https://assets.st-note.com/img/1681354383427-hE0DGVWMgP.png?width=1200)
![](https://assets.st-note.com/img/1681354628837-CEeMAXEOkh.png)
![](https://assets.st-note.com/img/1681367848315-Sw4KtGBwDN.png?width=1200)
![](https://assets.st-note.com/img/1681367939141-VzWwwjYSji.png?width=1200)
![](https://assets.st-note.com/img/1681368443883-uNwa9O2pLp.png?width=1200)
![](https://assets.st-note.com/img/1681368179796-nIxBU71JBu.png)
必ずしもピクセル単位でレイアウトを決めるのではなく、テキスト文などと同じく文字数で幅などは決めていることがわかりました。
一寸ボタンが小さいなどの不満はありますが、最終的には適宜決めるということで次に進みます。
![](https://assets.st-note.com/img/1681368603563-yowQXxabCP.png?width=1200)
import tkinter as tk
import random
# ボタンがクリックされたときの処理
def btn_click(hand):
# プレイヤーの手を取得
player_hand = hand
# コンピュータの手をランダムに取得
hands = ["グー", "チョキ", "パー"]
computer_hand = random.choice(hands)
# 結果を表示
result_label.configure(text=f"あなたは {player_hand} を出しました\nコンピュータは {computer_hand} を出しました")
# ウィンドウを作成
window = tk.Tk()
window.title("じゃんけんゲーム")
window.geometry("300x500")
# ラベルを作成
result_label = tk.Label(window, text="", font=("Helvetica", 14))
result_label.place(x=10, y=100)
# ボタンを作成
gu_btn = tk.Button(window, text="グー", font=("Helvetica", 14), command=lambda: btn_click("グー"))
choki_btn = tk.Button(window, text="チョキ", font=("Helvetica", 14), command=lambda: btn_click("チョキ"))
pa_btn = tk.Button(window, text="パー", font=("Helvetica", 14), command=lambda: btn_click("パー"))
gu_btn.place(x=20, y=400)
choki_btn.place(x=120, y=400)
pa_btn.place(x=220, y=400)
# ウィンドウを表示
window.mainloop()
![](https://assets.st-note.com/img/1681370876670-sxinaiIAz0.png?width=1200)
![](https://assets.st-note.com/img/1681372780796-lyeFlhsvPB.png)
![](https://assets.st-note.com/img/1681372949626-dp22ytpvDU.png)
とりあえずは相手の手の表示をしてもらいたいとこです。下方の3個の一つをクリックすると相手の手も決まります。ここまではできています。
![](https://assets.st-note.com/img/1681374183299-xus4YiUUDf.png?width=1200)
ちょっとうまく表示されませんでした。話し方を変えて次に進みました
![](https://assets.st-note.com/img/1681374668757-SJCJWAvqKb.png?width=1200)
import tkinter as tk
import random
# ボタンがクリックされたときの処理
def btn_click(hand):
# プレイヤーの手を取得
player_hand = hand
# コンピュータの手をランダムに取得
hands = ["グー", "チョキ", "パー"]
computer_hand = random.choice(hands)
# 勝敗の判定
if player_hand == computer_hand:
result_label.configure(text="引き分け", bg="yellow")
player_btn.configure(bg="yellow")
computer_btn.configure(bg="yellow")
elif (player_hand == "グー" and computer_hand == "チョキ") or \
(player_hand == "チョキ" and computer_hand == "パー") or \
(player_hand == "パー" and computer_hand == "グー"):
result_label.configure(text=f"あなたの勝ち!({player_hand} vs {computer_hand})", bg="blue")
player_btn.configure(bg="blue")
computer_btn.configure(bg="red")
else:
result_label.configure(text=f"コンピュータの勝ち…({computer_hand} vs {player_hand})", bg="red")
player_btn.configure(bg="red")
computer_btn.configure(bg="blue")
# ウィンドウを作成
window = tk.Tk()
window.title("じゃんけんゲーム")
window.geometry("300x500")
# ラベルを作成
result_label = tk.Label(window, text="相手の手", font=("Helvetica", 14), bg="white", width=20, height=2)
result_label.place(x=50, y=100)
# ボタンを作成
player_btn = tk.Button(window, text="グー", font=("Helvetica", 14), command=lambda: btn_click("グー"), width=8, height=2)
computer_btn = tk.Button(window, text="?", font=("Helvetica", 14), state="disabled", width=8, height=2)
player_btn.place(x=20, y=400)
computer_btn.place(x=220, y=400)
# ウィンドウを表示
window.mainloop()
![](https://assets.st-note.com/img/1681376965633-Conoh5FqAA.png)
![](https://assets.st-note.com/img/1681377066681-03L8zdi8z7.png)
ボタンの配置がおかしいですが、一応ジャンケンをうまくやっているようですね。もう一押しですね(^^♪
![](https://assets.st-note.com/img/1681389335807-TLfCqXOpRp.png?width=1200)
import tkinter as tk
import random
def play_game():
# コンピュータの手をランダムに選択
hands = ['グー', 'チョキ', 'パー']
computer_hand = random.choice(hands)
# プレイヤーが選択した手を取得
player_hand = player_var.get()
# 結果を判定
result_label.config(fg='black')
if player_hand == computer_hand:
result_label.config(text='引き分け', fg='yellow')
elif (player_hand == 'グー' and computer_hand == 'チョキ') or \
(player_hand == 'チョキ' and computer_hand == 'パー') or \
(player_hand == 'パー' and computer_hand == 'グー'):
result_label.config(text='勝ち', fg='blue')
else:
result_label.config(text='負け', fg='red')
# ウィンドウを作成
root = tk.Tk()
root.title('じゃんけん')
# プレイヤーの手を選択するためのボタンを作成
player_var = tk.StringVar()
player_var.set('グー')
rock_btn = tk.Radiobutton(root, text='グー', variable=player_var, value='グー')
scissors_btn = tk.Radiobutton(root, text='チョキ', variable=player_var, value='チョキ')
paper_btn = tk.Radiobutton(root, text='パー', variable=player_var, value='パー')
rock_btn.pack(side='left', padx=10, pady=10)
scissors_btn.pack(side='left', padx=10, pady=10)
paper_btn.pack(side='left', padx=10, pady=10)
# コンピュータの手を表示するラベルを作成
computer_label = tk.Label(root, text='相手の手')
computer_label.place(x=10, y=100)
computer_var = tk.StringVar()
computer_var.set('-')
computer_hand_label = tk.Label(root, textvariable=computer_var)
computer_hand_label.place(x=10, y=200)
# 結果を表示するラベルを作成
result_label = tk.Label(root, text='結果')
result_label.place(x=10, y=250)
# プレイヤーが手を選択した後にじゃんけんをするためのボタンを作成
play_btn = tk.Button(root, text='じゃんけん', command=play_game)
play_btn.place(x=10, y=300)
root.geometry('300x500')
root.mainloop()
scssということで上記を提案してくれました。Radiobuttonを使用しています。
結果は下記のようになります。
![](https://assets.st-note.com/img/1681390213763-dB14TkPzkR.png)
ちょっとChatGTPとコミュニケーションが取れなくなってきた感じです。このプログラムはRadiobuttonに自分の手を設定してから「ジャンケン・ポン」といった感じでしょうか。それはそれでありかもしれませんが、事前に手を明かすというのはあまり感心しません。
修正をお願いして、次のコードを出してくれました。
import tkinter as tk
import random
# ボタンがクリックされたときの処理
def btn_click(hand):
# プレイヤーの手を取得
player_hand = hand
# コンピュータの手をランダムに取得
hands = ["グー", "チョキ", "パー"]
computer_hand = random.choice(hands)
# 勝敗の判定
if player_hand == computer_hand:
result_label.configure(text="引き分け", bg="yellow")
player_btn.configure(bg="yellow")
computer_btn.configure(bg="yellow")
elif (player_hand == "グー" and computer_hand == "チョキ") or \
(player_hand == "チョキ" and computer_hand == "パー") or \
(player_hand == "パー" and computer_hand == "グー"):
result_label.configure(text=f"あなたの勝ち!({player_hand} vs {computer_hand})", bg="blue")
player_btn.configure(bg="blue")
computer_btn.configure(bg="red")
else:
result_label.configure(text=f"コンピュータの勝ち…({computer_hand} vs {player_hand})", bg="red")
player_btn.configure(bg="red")
computer_btn.configure(bg="blue")
# 相手の手を表示
computer_btn.configure(text=computer_hand)
# ウィンドウを作成
window = tk.Tk()
window.title("じゃんけんゲーム")
window.geometry("300x500")
# ラベルを作成
result_label = tk.Label(window, text="相手の手", font=("Helvetica", 14), bg="white", width=20, height=2)
result_label.place(x=50, y=100)
# ボタンを作成
player_btn_rock = tk.Button(window, text="グー", font=("Helvetica", 14), command=lambda: btn_click("グー"), width=8, height=2)
player_btn_scissors = tk.Button(window, text="チョキ", font=("Helvetica", 14), command=lambda: btn_click("チョキ"), width=8, height=2)
player_btn_paper = tk.Button(window, text="パー", font=("Helvetica", 14), command=lambda: btn_click("パー"), width=8, height=2)
computer_btn = tk.Button(window, text="?", font=("Helvetica", 14), state="disabled", width=8, height=2)
player_btn_rock.place(x=20, y=400)
player_btn_scissors.place(x=120, y=400)
player_btn_paper.place(x=220, y=400)
computer_btn.place(x=146, y=200)
# ウィンドウを表示
window.mainloop()
結果がこれです。
![](https://assets.st-note.com/img/1681391140992-OebfGPQHlj.png)
![](https://assets.st-note.com/img/1681391203887-3tnU2FwYMm.png)
いろいろやって次で自分の手に色がつくようになりました。
import tkinter as tk
import random
class Game:
def __init__(self, master):
self.master = master
master.title("じゃんけんゲーム")
master.geometry("300x500")
self.result_label = tk.Label(master, text="相手の手", font=("Helvetica", 14), bg="white", width=20, height=2)
self.result_label.place(x=50, y=100)
self.player_hands = [
HandButton(master, "グー", "player", 20),
HandButton(master, "チョキ", "player", 120),
HandButton(master, "パー", "player", 220)
]
self.computer_hands = [
HandButton(master, "?", "computer", 120),
]
self.player_hands[0].button.invoke()
def set_color(self, player_hand, computer_hand):
for hand in self.player_hands:
if hand.hand == player_hand:
hand.button.configure(bg="blue")
else:
hand.button.configure(bg="white")
for hand in self.computer_hands:
if hand.hand == computer_hand:
hand.button.configure(bg="red")
else:
hand.button.configure(bg="white")
def btn_click(self, hand):
player_hand = hand
computer_hand = random.choice(["グー", "チョキ", "パー"])
if player_hand == computer_hand:
self.result_label.configure(text="引き分け", bg="yellow")
self.set_color(player_hand, computer_hand)
elif (player_hand == "グー" and computer_hand == "チョキ") or \
(player_hand == "チョキ" and computer_hand == "パー") or \
(player_hand == "パー" and computer_hand == "グー"):
self.result_label.configure(text=f"あなたの勝ち!({player_hand} vs {computer_hand})", bg="blue")
self.set_color(player_hand, computer_hand)
else:
self.result_label.configure(text=f"コンピュータの勝ち…({computer_hand} vs {player_hand})", bg="red")
self.set_color(player_hand, computer_hand)
class HandButton:
def __init__(self, master, hand, player_type, x):
self.hand = hand
self.button = tk.Button(master, text=hand, font=("Helvetica", 14), command=lambda: game.btn_click(hand), width=8, height=2)
self.button.place(x=x, y=400)
if player_type == "computer":
self.button.configure(state="disabled")
self.button.place(x=220, y=100)
root = tk.Tk()
game = Game(root)
root.mainloop()
![](https://assets.st-note.com/img/1681394132467-Qv0b55Vl7n.png)
プログラムも大分難しくなって、僕の手には負えそうにないのでまた、なんかの機会にとしたいと思います
4. ジャンケンその2
気持ちを切り替えて、もう一度、仕様を考え直した。自分の手の入力方法をボタンでなく、キー入力にしてみると簡単な使用になることに気が付いた。
ジャンケンの仕様を変えてみます。
・ 画面の大きさを 300*400にします
・ 上方 y=100に相手の手を示すラベルをおきます
・ 中央 y=200に結果を示すラベルをおきます
・ 下方 y=300に自分の手を示すラベルをおきます
・ 上方の相手の手はランダムにグー、チョキ、パーを取り、それをラベルに書きます
・ 下方の自分の手はキー入力で決めます
・ キーAがグー、キーSがチョキ、キーDがパーに対応します
・ キー入力時がゲーム開始です
・ じゃんけんの結果を中央の結果ラベルに示します。
・ グー、チョキ、パーに応じて相手の手、自分の手ラベルにあか、黄色、青の色を塗ります
こんなプログラムを作ってください
ちょっと手直しもありますが、次のようなコードを作ってくれました。
import tkinter as tk
import random
class JankenGame:
def __init__(self, master):
self.master = master
self.master.title("じゃんけんゲーム")
self.master.geometry("300x400")
self.result_label = tk.Label(self.master, text="じゃんけんを開始", font=("Helvetica", 20))
self.result_label.place(relx=0.5, rely=0.4, anchor="center")
self.cpu_label = tk.Label(self.master, text="相手の手", font=("Helvetica", 20))
self.cpu_label.place(relx=0.5, rely=0.25, anchor="center")
self.player_label = tk.Label(self.master, text="自分の手", font=("Helvetica", 20))
self.player_label.place(relx=0.5, rely=0.6, anchor="center")
self.master.bind("<Key>", self.play_janken)
def play_janken(self, event):
player_choice = ""
if event.char == "a":
player_choice = "グー"
elif event.char == "s":
player_choice = "チョキ"
elif event.char == "d":
player_choice = "パー"
else:
return
cpu_choice = random.choice(["グー", "チョキ", "パー"])
result = self.check_result(player_choice, cpu_choice)
self.player_label.config(text=f"あなたの手:{player_choice}", bg=self.get_color(player_choice))
self.cpu_label.config(text=f"相手の手:{cpu_choice}", bg=self.get_color(cpu_choice))
self.result_label.config(text=result)
def check_result(self, player_choice, cpu_choice):
if player_choice == cpu_choice:
return "引き分け"
elif (player_choice == "グー" and cpu_choice == "チョキ") or \
(player_choice == "チョキ" and cpu_choice == "パー") or \
(player_choice == "パー" and cpu_choice == "グー"):
return "あなたの勝ち"
else:
return "あなたの負け"
def get_color(self, choice):
if choice == "グー":
return "red"
elif choice == "チョキ":
return "yellow"
elif choice == "パー":
return "blue"
if __name__ == "__main__":
root = tk.Tk()
app = JankenGame(root)
root.mainloop()
![](https://assets.st-note.com/img/1681449164641-otfgMv1OaS.png)
![](https://assets.st-note.com/img/1681449305552-YENaTgLKuq.png)
あまり見栄えはよくないけれど、とりあえずは思ったものができた。見栄えをよくするのはまた次の段階にする。ここで使ったのはラベルだけである。
5. まとめ
tkinterモジュールの簡単な使い方を体験した。
簡単なボタン、ラベル、テキスト入力は理解できたかなと思う。ジャンケンのような簡単なモデルでも、ボタン、ラベルの使い方でいろいろと違ってくる。ラジオボタンを使って入力するのがいいか、テキストボックスを用いて一つのボタンで「ジャンケンポン」とやるのが今となってはいい気がする。
自分のイメージにこだわった気がする。最初にそれも相談した方がよかったかも。
まだ、いろいろとあるけれど。とりあえずはゲームのコード作成なのでpygameに次は進みたい。
この記事が気に入ったらサポートをしてみませんか?