textinput()だけじゃない!Python Turtleでユーザー入力を扱う代替手法
turtle.textinput()
とは何か?
turtle.textinput(title, prompt)
は、Pythonのturtle
グラフィックスライブラリで提供される関数の一つで、ユーザーからのテキスト入力を受け付けるためのポップアップダイアログボックスを表示します。
主に、タートルグラフィックスで描画中に、ユーザーに何らかの情報を入力してもらい、その入力値に基づいてプログラムの動作を変更したい場合などに利用されます。
引数
turtle.textinput()
には2つの引数が必要です。
-
title
(文字列):- 表示されるダイアログボックスのタイトルバーに表示される文字列です。ダイアログボックスの内容を簡潔に説明するために使われます。
- 例:「ユーザー入力」
-
prompt
(文字列):- ダイアログボックス内に表示されるメッセージ、またはユーザーへの指示です。ユーザーに何を入力してほしいのかを具体的に示します。
- 例:「お名前を入力してください:」
戻り値
- ユーザーが「キャンセル」をクリックした場合、
None
が返されます。 - ユーザーが何も入力せずに「OK」をクリックした場合、空の文字列
""
が返されます。 - ユーザーがダイアログボックスにテキストを入力して「OK」をクリックした場合、その入力された文字列が戻り値として返されます。
使用例
以下に簡単な使用例を示します。
import turtle
# タートルスクリーンの設定
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.title("テキスト入力の例")
# ユーザーに名前を尋ねる
user_name = turtle.textinput("名前の入力", "あなたのお名前は何ですか?")
# 入力に応じた処理
if user_name is None:
print("入力がキャンセルされました。")
message = "入力がキャンセルされました。"
elif user_name == "":
print("何も入力されませんでした。")
message = "何も入力されませんでした。"
else:
print(f"こんにちは、{user_name}さん!")
message = f"こんにちは、{user_name}さん!"
# タートルを使ってメッセージを表示
pen = turtle.Turtle()
pen.hideturtle() # タートル(矢印)を非表示にする
pen.penup() # ペンを上げて、描画せずに移動
pen.goto(0, 50) # 表示位置に移動
pen.write(message, align="center", font=("Arial", 16, "normal"))
# クリックでウィンドウを閉じる
screen.exitonclick()
上記のコードを実行すると、以下の手順で動作します。
- まず、
turtle
グラフィックウィンドウが表示されます。 - 同時に、「名前の入力」というタイトルのポップアップダイアログボックスが表示され、「あなたのお名前は何ですか?」というプロンプトが表示されます。
- ユーザーがテキストフィールドに名前を入力し、「OK」をクリックすると、その名前が
user_name
変数に格納されます。 - タートルグラフィックウィンドウ上に、入力された名前に応じたメッセージが表示されます。
- もし「キャンセル」がクリックされたり、何も入力されなかったりした場合は、それに応じたメッセージが表示されます。
turtle.textinput()
は比較的シンプルな関数ですが、いくつかのポイントで問題が発生することがあります。
エラー: NameError: name 'turtle' is not defined
これは、turtle
モジュールが正しくインポートされていない場合に発生する最も一般的なエラーです。
-
トラブルシューティング
- 必ずコードの冒頭に
import turtle
を記述してください。 これにより、turtle
モジュール内のすべての関数をturtle.
プレフィックスを付けて呼び出せるようになります。import turtle # ... user_input = turtle.textinput("タイトル", "プロンプト")
- もし
from turtle import *
のようにインポートしている場合は、turtle.
プレフィックスなしで関数を呼び出します(例:textinput("タイトル", "プロンプト")
)。しかし、一般的にはimport turtle
を使用する方が推奨されます。
- 必ずコードの冒頭に
-
import turtle
がコードの先頭にない。from turtle import *
のように個別の関数をインポートしている場合でも、turtle
プレフィックスを付けて呼び出そうとしている(例:textinput()
ではなくturtle.textinput()
を使用している)。
エラー: TypeError: textinput() missing 2 required positional arguments: 'title' and 'prompt'
これは、title
とprompt
の2つの引数が正しく渡されていない場合に発生します。
-
トラブルシューティング
title
とprompt
の両方を文字列として指定しているか確認してください。# 良い例 user_name = turtle.textinput("あなたの名前", "お名前を入力してください:") # 悪い例 (引数が足りない) # user_name = turtle.textinput() # user_name = turtle.textinput("あなたの名前") # 悪い例 (引数の型が違う) # user_name = turtle.textinput(123, 456)
-
原因
turtle.textinput()
を引数なしで呼び出している。- 引数を1つしか渡していない。
- 引数の型が間違っている(例: 数値を渡している)。
エラー: ダイアログボックスが表示されない/プログラムがフリーズする
これは、turtle
グラフィック環境が正しく設定されていない、またはイベントループが開始されていない場合に起こりえます。
-
トラブルシューティング
- プログラムの最後に
turtle.done()
またはscreen.mainloop()
を記述しているか確認してください。 これらは、turtle
グラフィックウィンドウをアクティブに保ち、ユーザーインタラクションを処理するために必要です。textinput()
は、ウィンドウが表示されている状態でなければ機能しません。import turtle screen = turtle.Screen() # スクリーンオブジェクトの作成 screen.setup(width=600, height=400) user_input = turtle.textinput("入力", "何か入力してください:") print(f"入力された値: {user_input}") turtle.done() # または screen.mainloop()
turtle.textinput()
を呼び出す前に、turtle.Screen()
でスクリーンオブジェクトを作成していることを確認してください。多くの場合、turtle
モジュールは自動的にスクリーンを設定しますが、明示的に行うことで安定性が増します。
- プログラムの最後に
-
原因
turtle.Screen()
オブジェクトを作成していない、またはその後にtextinput()
を呼び出しているにも関わらず、GUIイベントループ(screen.mainloop()
やturtle.done()
など)が開始されていない。turtle
の環境がうまく初期化されていない。
想定外の戻り値: None や空文字列 ""
これはエラーではありませんが、ユーザーの操作によってtextinput()
が返す値が異なるため、これらを適切に処理しないとプログラムが予期せぬ動作をする可能性があります。
-
状況
- ユーザーがダイアログで「キャンセル」をクリックした場合: 戻り値は
None
- ユーザーが何も入力せずに「OK」をクリックした場合: 戻り値は空文字列
""
- ユーザーがダイアログで「キャンセル」をクリックした場合: 戻り値は
環境依存の問題: ダイアログの表示位置や見た目
これはエラーというよりは、動作環境によってtextinput()
のダイアログの表示位置や見た目が異なることがあるという注意点です。
-
トラブルシューティング
- これは通常、コードの問題ではありません。もしダイアログが画面外に表示されるなどの問題がある場合、OSの設定やディスプレイの解像度を確認してみてください。一般的には、ユーザーが手動でダイアログを移動できます。
- 見た目のカスタマイズは、
turtle.textinput()
ではできません。より高度なGUI入力が必要な場合は、tkinter
(turtle
が内部で使用しているGUIライブラリ)を直接使用することを検討する必要があります。
-
原因
- 使用しているOS(Windows, macOS, Linux)やPythonのバージョン、Tkinterのバージョンによって、GUIダイアログの挙動が微妙に異なる場合があります。
turtle.textinput()
は、ユーザーからのテキスト入力を受け取り、それに基づいてタートルグラフィックスの動作を制御するのに非常に便利です。
例1: ユーザーの名前を表示する
最も基本的な例で、ユーザーに名前を入力してもらい、それをタートルグラフィックスで表示します。
import turtle
# 1. スクリーンオブジェクトの準備
screen = turtle.Screen()
screen.setup(width=600, height=400) # スクリーンサイズを設定
screen.title("名前表示プログラム") # ウィンドウのタイトル
# 2. ユーザーからの入力を受け取る
# textinput(タイトル, プロンプト)
user_name = turtle.textinput("名前の入力", "あなたのお名前は何ですか?")
# 3. 入力値に応じた処理
# Noneは「キャンセル」がクリックされた場合
# ""(空文字列)は何も入力せずに「OK」がクリックされた場合
if user_name is None:
display_message = "入力をキャンセルしました。"
elif user_name == "":
display_message = "何も入力されませんでした。"
else:
display_message = f"こんにちは、{user_name}さん!"
# 4. タートルでメッセージを表示
pen = turtle.Turtle()
pen.hideturtle() # タートル(矢印)を非表示
pen.penup() # ペンを上げて描画せずに移動
pen.goto(0, 50) # 表示位置を設定
pen.write(display_message, align="center", font=("Arial", 20, "normal"))
# 5. ウィンドウを閉じるまで待機
screen.exitonclick() # ウィンドウクリックで終了
解説
if/elif/else
を使って、user_name
の値(None
、空文字列、実際の文字列)に応じたメッセージを作成し、pen.write()
で画面に表示しています。- ユーザーの入力(またはキャンセル)に応じて、
user_name
変数に値が格納されます。 turtle.textinput("名前の入力", "あなたのお名前は何ですか?")
で、ユーザーに名前の入力を促すダイアログが表示されます。
例2: ユーザーの入力に基づいて図形の色を変更する
ユーザーに好きな色を入力してもらい、その色で円を描画する例です。
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.title("色変更プログラム")
# 1. ユーザーから色名を入力してもらう
color_name = turtle.textinput("色の選択", "好きな色を入力してください(例: red, blue, green, purple):")
# 2. タートルオブジェクトの準備
my_turtle = turtle.Turtle()
my_turtle.shape("turtle") # タートルの形をカメにする
my_turtle.speed(1) # 描画速度を遅くする
# 3. 入力された色に基づいて描画
if color_name is None:
print("色の入力がキャンセルされました。")
my_turtle.color("black") # デフォルトの色を設定
my_turtle.write("色選択をキャンセルしました。", align="center", font=("Arial", 16, "normal"))
elif color_name == "":
print("何も色を入力しませんでした。")
my_turtle.color("gray") # デフォルトの色を設定
my_turtle.write("何も色を入力しませんでした。", align="center", font=("Arial", 16, "normal"))
else:
try:
# 入力された色を設定
my_turtle.color(color_name.lower()) # 小文字に変換して設定
my_turtle.pensize(3) # ペンの太さ
my_turtle.circle(100) # 半径100の円を描画
my_turtle.penup()
my_turtle.goto(0, -120)
my_turtle.write(f"円の色は {color_name} です。", align="center", font=("Arial", 16, "normal"))
except turtle.TurtleGraphicsError:
# 認識できない色が入力された場合のエラーハンドリング
print(f"無効な色名が入力されました: {color_name}")
my_turtle.color("red")
my_turtle.write("無効な色名です。", align="center", font=("Arial", 16, "normal"))
# 4. ウィンドウを閉じるまで待機
screen.exitonclick()
解説
.lower()
を使って入力された文字列を小文字に変換することで、大文字・小文字の入力ミスに対応しています(例: "Red" も "red" として扱われる)。try-except
ブロックを使用して、ユーザーが有効な色名("red"
,"blue"
など)を入力したかどうかをチェックしています。turtle.color()
は、認識できない色名が渡されるとTurtleGraphicsError
を発生させるため、これでエラーを捕捉し、適切なメッセージを表示できます。color_name = turtle.textinput(...)
で色名を受け取ります。
例3: ユーザーの入力でタートルを移動させる(コマンドライン風)
ユーザーにコマンド(例: "forward 50", "left 90")を入力してもらい、タートルを制御する例です。
import turtle
screen = turtle.Screen()
screen.setup(width=800, height=600)
screen.title("タートルコマンド入力")
my_turtle = turtle.Turtle()
my_turtle.shape("arrow")
my_turtle.speed(3) # 速度を少し速く
message = "コマンドを入力してください (例: forward 100, left 90, exit)\n" \
"キャンセルの場合は何も入力せずにOKかキャンセル。"
while True:
command_input = turtle.textinput("タートルコマンド", message)
if command_input is None:
print("コマンド入力がキャンセルされました。プログラムを終了します。")
break # ループを抜けて終了
elif command_input == "":
print("何も入力されませんでした。再入力を促します。")
continue # ループの先頭に戻る
else:
# 入力されたコマンドをスペースで分割
parts = command_input.lower().split()
action = parts[0] # 最初の部分がアクション(例: forward, left)
value = 0
if len(parts) > 1:
try:
value = float(parts[1]) # 2番目の部分が値(例: 100, 90)
except ValueError:
print(f"無効な値: '{parts[1]}'")
continue
if action == "forward":
my_turtle.forward(value)
elif action == "backward":
my_turtle.backward(value)
elif action == "left":
my_turtle.left(value)
elif action == "right":
my_turtle.right(value)
elif action == "clear":
my_turtle.clear() # 描画をクリア
my_turtle.penup()
my_turtle.home() # 原点に戻る
my_turtle.pendown()
elif action == "exit":
print("exitコマンドが入力されました。プログラムを終了します。")
break # ループを抜けて終了
else:
print(f"不明なコマンド: {action}")
# コマンド実行後に、次の入力を促すためのメッセージを更新(今回は不要だが、複雑な場合は有効)
# ウィンドウを閉じるまで待機
screen.exitonclick()
break
文を使ってループを終了させる条件("exit"入力またはキャンセル)を設定しています。try-except ValueError
で、数値が必要な引数(距離や角度)に、数値以外のものが入力された場合のエラーを処理しています。if/elif
で、action
の値に基づいてタートルのメソッド(forward()
,left()
など)を呼び出しています。command_input.lower().split()
で、入力された文字列を小文字に変換し、スペースで分割してコマンドと引数に分けています。while True:
ループを使って、ユーザーが「exit」と入力するか、キャンセルするまで繰り返し入力を求めます。
主に以下の方法が挙げられます。
input()
関数を使用するtkinter
を直接使用する- イベントハンドリング(キーボード入力など)を利用する
input() 関数を使用する
これは最もシンプルで基本的な代替方法です。input()
関数は、プログラムが実行されているコンソール(ターミナルやコマンドプロンプト)でユーザーからのテキスト入力を受け付けます。
-
使用例
import turtle screen = turtle.Screen() screen.setup(width=600, height=400) screen.title("input()関数での入力例") # コンソールで入力を促す user_name = input("コンソールで名前を入力してください: ") # タートルでメッセージ表示 pen = turtle.Turtle() pen.hideturtle() pen.penup() pen.goto(0, 50) if user_name: # 何か入力された場合 display_message = f"こんにちは、{user_name}さん!" else: # 何も入力されなかった場合 display_message = "何も入力されませんでした。" pen.write(display_message, align="center", font=("Arial", 20, "normal")) # グラフィックウィンドウが表示され続けるように screen.exitonclick()
解説
このコードを実行すると、まずコンソールに「コンソールで名前を入力してください: 」と表示され、ユーザーがそこで入力するのを待ちます。入力後、その値がuser_name
に代入され、タートルグラフィックウィンドウにメッセージが表示されます。 -
欠点
- 入力がGUIダイアログではなく、コンソールで行われる。そのため、ユーザーはコンソールウィンドウに切り替えて入力する必要がある。
turtle
グラフィックウィンドウ上にプロンプトが表示されないため、ユーザー体験が分断される。- 入力中のプログラムのグラフィック描画は停止する(
turtle.textinput()
と同様に、同期的な入力)。
-
- 非常にシンプルで、追加のモジュールや複雑な設定は不要。
turtle
グラフィックウィンドウとは独立して動作するため、プログラムのフローをブロックせずにユーザー入力を待つことができる(ただし、コンソールがアクティブである必要がある)。
tkinter を直接使用する
turtle
モジュールは、内部的にPython標準のGUIライブラリであるtkinter
を使用しています。turtle.textinput()
もtkinter
の機能(tkinter.simpledialog.askstring
など)をラップしたものです。tkinter
を直接使うことで、より柔軟なダイアログボックスやカスタムGUI要素を作成できます。
-
使用例
import turtle import tkinter as tk from tkinter import simpledialog, messagebox screen = turtle.Screen() screen.setup(width=600, height=400) screen.title("tkinterでの入力例") # Tkinterのルートウィンドウを取得(turtleが内部で使っているものを再利用) root = screen._root # 非公開属性なので注意が必要 # ユーザーからの入力を受け取るカスタムダイアログ(例: simpledialog.askstringの直接使用) # textinput()の内部もこれに近い user_age_str = simpledialog.askstring("年齢の入力", "あなたの年齢を入力してください:", parent=root) # タートルでメッセージ表示 pen = turtle.Turtle() pen.hideturtle() pen.penup() pen.goto(0, 50) if user_age_str is None: display_message = "年齢入力をキャンセルしました。" elif user_age_str == "": display_message = "何も入力されませんでした。" else: try: user_age = int(user_age_str) display_message = f"あなたは{user_age}歳ですね!" except ValueError: display_message = "無効な年齢が入力されました。" messagebox.showerror("エラー", "年齢は数字で入力してください!", parent=root) # エラーメッセージボックスも表示可能 pen.write(display_message, align="center", font=("Arial", 20, "normal")) # ウィンドウを閉じるまで待機 screen.exitonclick()
解説
tkinter.simpledialog.askstring()
は、turtle.textinput()
と非常によく似たダイアログを生成します。parent=root
を指定することで、turtle
のウィンドウが親ウィンドウとなり、ダイアログが適切に表示されます。tkinter.messagebox.showerror()
のように、tkinter
の他のGUI要素も利用して、よりリッチなユーザー体験を提供できます。- より複雑な入力フォーム(複数の入力フィールド、ラジオボタン、チェックボックスなど)が必要な場合は、
tkinter.Tk()
で新しいウィンドウを作成し、その中にtkinter.Entry
,tkinter.Button
などのウィジェットを配置して構築します。
-
欠点
tkinter
の知識が必要となり、turtle.textinput()
よりもコードが複雑になる。- 学習コストがかかる。
-
利点
- 完全にカスタマイズ可能なダイアログボックスを作成できる。 (例: 入力フィールドの数、ボタンの種類、レイアウトなど)
- エラーチェックや入力検証をより細かく実装できる。
turtle
ウィンドウと同じプロセス内で、より統合されたGUIを実現できる。
イベントハンドリング(キーボード入力など)を利用する
turtle.textinput()
やinput()
とは異なり、ユーザーがキーボードを叩くたびに、または特定のキーが押されたときに、プログラムが反応するように設定する方法です。これは、リアルタイムのゲームやインタラクティブな描画アプリケーションでよく使われます。
-
使用例
import turtle screen = turtle.Screen() screen.setup(width=600, height=400) screen.title("キーボード入力例") screen.tracer(0) # アニメーションを高速化(描画を一度に更新) my_turtle = turtle.Turtle() my_turtle.shape("turtle") my_turtle.penup() my_turtle.speed(0) # 画面に表示するテキスト current_text = "" text_display = turtle.Turtle() text_display.hideturtle() text_display.penup() text_display.goto(0, 100) # テキスト表示位置 # キーイベントハンドラー def handle_keypress(key): global current_text text_display.clear() # 前のテキストをクリア if key == "Return": # Enterキーが押されたら text_display.write(f"入力完了: {current_text}", align="center", font=("Arial", 16, "normal")) # ここで current_text を使った処理を行う print(f"入力された文字列: {current_text}") current_text = "" # テキストをリセット elif key == "BackSpace": current_text = current_text[:-1] # 最後の文字を削除 else: current_text += key # 押されたキーの文字を追加 text_display.write(f"入力中: {current_text}", align="center", font=("Arial", 16, "normal")) screen.update() # 画面を更新 # キーイベントをリスナーに登録 screen.onkeypress(lambda: handle_keypress("a"), "a") # 'a'キー screen.onkeypress(lambda: handle_keypress("b"), "b") # 'b'キー # ... 他のキーも同様に登録 screen.onkeypress(lambda: handle_keypress("Return"), "Return") # Enterキー screen.onkeypress(lambda: handle_keypress("BackSpace"), "BackSpace") # BackSpaceキー # すべてのキーボードイベントをリッスンするための設定 # screen.textinput()が使えない環境では、これで代替する # ただし、一般的な文字入力を実装するには、全てのキーイベントを拾う必要があり非常に大変 # 代わりに、onkey()やonkeypress()を文字ごとに登録するか、 # 実際にはtkinterのEntryウィジェットを使う方が現実的 # 簡略化のため、ここではいくつかのキーのみを例として登録 # 実際のテキスト入力には、これだけでは不十分 screen.listen() # キーイベントを待ち受ける状態にする # タートルを動かす(例として) my_turtle.goto(-100, 0) my_turtle.pendown() my_turtle.forward(200) screen.mainloop() # イベントループを開始
解説
screen.onkeypress(関数, キー名)
を使うことで、特定のキーが押されたときに指定した関数が呼び出されます。handle_keypress
関数内で、current_text
変数に押されたキーの文字を追加していき、Enterキーで入力を確定するようなロジックを実装しています。screen.tracer(0)
とscreen.update()
を使うことで、アニメーションを高速化し、テキスト表示のちらつきを抑えています。- 注意点
この方法で一般的なテキスト入力フィールドを実装するのは非常に手間がかかります。全ての英数字、記号、スペース、Deleteキーなどを個別に処理する必要があります。このため、まとまったテキスト入力が必要な場合は、上記2のtkinter
のEntry
ウィジェットを直接使う方がはるかに現実的です。
-
欠点
- テキスト入力としてまとまった文字列を受け取るのではなく、一文字ずつのキー入力として処理する必要がある。
- 入力フィールドのようなGUI要素を自分で実装する必要がある(または非常に限定的なテキスト入力になる)。
- 実装が他の方法よりも複雑になる傾向がある。
-
利点
- 非同期的な入力処理が可能。 プログラムの実行をブロックせずに、ユーザーのキーボード操作に即座に反応できる。
- ゲームのようなインタラクティブなアプリケーションに最適。
- リアルタイムでキーボード入力に反応させたい、ゲームのようなアプリケーションの場合
turtle.onkeypress()
などのイベントハンドリング(ただし、完全なテキスト入力の実装は複雑) - GUIダイアログでより高度なカスタマイズやエラー処理を行いたい場合
tkinter
を直接使う(特にtkinter.simpledialog
やtkinter.Entry
) - 最もシンプルで手軽にコンソールから入力したい場合
input()