turtle.onrelease()

2025-06-06

使い方

基本的な使い方は以下の通りです。

import turtle

# マウスボタンが離されたときに実行したい関数を定義します
def click_release_handler(x, y):
    print(f"マウスボタンが離されました。座標: ({x}, {y})")
    # ここに、ボタンが離されたときの処理を書きます

# スクリーンオブジェクトを取得します
screen = turtle.Screen()

# マウスボタンが離されたときに click_release_handler 関数を呼び出すように設定します
# デフォルトでは左クリック (ボタン1) に反応します
screen.onrelease(click_release_handler)

# 別のボタン(例: 右クリック = ボタン3)に反応させたい場合
# screen.onrelease(click_release_handler, btn=3)

# タートルグラフィックのイベントループを開始します
turtle.done()

詳細

  • screen.onrelease(fun, btn=1)
    • fun: マウスボタンが離されたときに呼び出される関数を指定します。この関数は、イベントが発生した際にマウスカーソルの x 座標と y 座標を引数として受け取る必要があります。
    • btn: どのマウスボタンに反応するかを指定します。
      • 1: 左クリック (デフォルト)
      • 2: 中央クリック (スクロールホイール)
      • 3: 右クリック

turtle.onrelease() の役割

turtle.onrelease() は、ユーザーがマウスボタンを「押している間」ではなく、「ボタンから指を離した瞬間」に何らかの処理を行いたい場合に非常に便利です。例えば:

  • インタラクションのトリガー
    ボタンが離されたときに、特定のイベントやアクションをトリガーする。
  • 描画の終了
    ユーザーがマウスボタンを押しながら線を描き、ボタンを離したときに描画を終了する。
  • ドラッグ&ドロップ操作の終了
    ユーザーがオブジェクトをドラッグし、目的の位置でマウスボタンを離したときに、そのオブジェクトを固定する。

turtle.onclick() との違い

よく似た関数に turtle.onclick() がありますが、これらは動作が異なります。

  • turtle.onrelease(fun, btn=1)
    マウスボタンが離されたときに指定された関数を実行します。
  • turtle.onclick(fun, btn=1)
    マウスボタンが**クリックされた(押された)**ときに指定された関数を実行します。


AttributeError: 'Turtle' object has no attribute 'onrelease'

エラーの原因
onrelease() メソッドは、Screen オブジェクト(画面全体)にイベントをバインドするために設計されています。個々の Turtle オブジェクトには onrelease() メソッドは存在しません。

間違ったコードの例

import turtle

t = turtle.Turtle()
# これは間違い!Turtleオブジェクトにはonreleaseがない
t.onrelease(some_function) 

解決策
Screen オブジェクトに対して onrelease() を呼び出す必要があります。

import turtle

screen = turtle.Screen() # スクリーンオブジェクトを取得
t = turtle.Turtle()

def handle_release(x, y):
    print(f"マウスが離されました: ({x}, {y})")

screen.onrelease(handle_release) # Screenオブジェクトにバインド
turtle.done()

イベントが全く発火しない/反応しない

エラーの原因
turtle グラフィックは、イベントループが実行されていないと、マウスイベントなどの外部からの入力を処理できません。

解決策
プログラムの最後に turtle.done() または screen.mainloop() を追加して、タートルグラフィックのイベントループを開始します。これにより、プログラムが終了せずにイベントを待ち続けます。

import turtle

screen = turtle.Screen()

def handle_release(x, y):
    print(f"マウスが離されました: ({x}, {y})")

screen.onrelease(handle_release)

# これを忘れるとイベントが処理されない
turtle.done() 
# または screen.mainloop()

関数に引数が渡されていない、または引数の数が間違っている

エラーの原因
onrelease() に渡す関数は、マウスが離されたときの x 座標と y 座標を受け取るために、2つの引数を持つ必要があります。引数の数が合わないとエラーになったり、期待通りの動作をしなかったりします。

間違ったコードの例

import turtle

screen = turtle.Screen()

def no_args_func(): # 引数がない
    print("マウスが離されました")

screen.onrelease(no_args_func) # エラーにはならないが、x, yが使えない

def one_arg_func(x): # 引数が1つだけ
    print(f"x座標: {x}")

screen.onrelease(one_arg_func) # TypeError: 'one_arg_func' takes 1 positional argument but 2 were given

解決策
イベントハンドラ関数が xy の2つの引数を受け取るように定義します。

import turtle

screen = turtle.Screen()

def correct_handler(x, y): # 2つの引数を受け取る
    print(f"マウスが離されました。座標: ({x}, {y})")

screen.onrelease(correct_handler)
turtle.done()

別のマウスボタンに反応させたい

エラーの原因
onrelease()btn 引数を指定しない場合、デフォルトで左クリック(ボタン1)に反応します。

解決策
btn 引数を使用して、特定のボタンに反応するように設定します。

  • btn=3: 右クリック
  • btn=2: 中央クリック (スクロールホイール)
  • btn=1: 左クリック
import turtle

screen = turtle.Screen()

def right_click_handler(x, y):
    print(f"右クリックが離されました: ({x}, {y})")

def middle_click_handler(x, y):
    print(f"中央クリックが離されました: ({x}, {y})")

screen.onrelease(right_click_handler, btn=3) # 右クリックにバインド
screen.onrelease(middle_click_handler, btn=2) # 中央クリックにバインド
screen.onrelease(lambda x, y: print(f"左クリックが離されました: ({x}, {y})"), btn=1) # 左クリックにバインド

turtle.done()

onclick() と onrelease() の混同

エラーの原因
onclick() はマウスボタンが押された瞬間に発火するのに対し、onrelease() はマウスボタンが離された瞬間に発火します。両者の違いを理解せず、どちらか一方を期待する動作のために使用している場合があります。

解決策
意図するイベントが「ボタンを押した瞬間」なのか「ボタンを離した瞬間」なのかを明確にし、適切なメソッド (onclick() または onrelease()) を使用します。

複数回のイベント登録や上書き

エラーの原因
同じマウスボタンに対して複数回 onrelease() を呼び出すと、通常は最後の呼び出しが以前のバインディングを上書きします。古いバインディングも保持したい場合は add=True を指定する必要があります。


import turtle

screen = turtle.Screen()

def handler1(x, y):
    print("ハンドラー1が実行されました")

def handler2(x, y):
    print("ハンドラー2が実行されました")

screen.onrelease(handler1) # 左クリックにhandler1をバインド
screen.onrelease(handler2) # 左クリックにhandler2をバインド(handler1は上書きされる)

# どちらも実行したい場合
# screen.onrelease(handler1, btn=1, add=True)
# screen.onrelease(handler2, btn=1, add=True)

turtle.done()

この例では、handler2 のみが実行されます。両方を実行したい場合は add=True を使います。

エラーの原因
スクリプトが最後まで実行されると、タートルグラフィックのウィンドウは自動的に閉じてしまいます。イベントリスナーを設定していても、イベントループが開始されていないと意味がありません。

解決策
turtle.done() または screen.mainloop() をプログラムの最後に必ず配置してください。これにより、ウィンドウがイベントを待ち続ける状態になります。

turtle.onrelease() をトラブルシューティングする際は、以下の点を確認してください。

  • onclick()onrelease() の違いを理解しているか?
  • 期待するマウスボタン (btn) を正しく指定しているか?
  • プログラムの最後に turtle.done() または screen.mainloop() があるか?
  • イベントハンドラ関数は2つの引数 (x, y) を受け取るか?
  • Screen オブジェクトで呼び出しているか? (turtle.Screen().onrelease())


例1: マウスを離した位置にタートルが移動する

この例では、ユーザーがマウスボタンを離した瞬間に、タートルがその位置に移動します。

import turtle

# スクリーンオブジェクトを取得
screen = turtle.Screen()
screen.setup(width=600, height=400) # ウィンドウサイズを設定
screen.title("マウスを離したら移動") # ウィンドウのタイトルを設定

# タートルを作成
my_turtle = turtle.Turtle()
my_turtle.shape("turtle")
my_turtle.color("blue")
my_turtle.speed(0) # 最速で移動

# マウスボタンが離されたときに実行される関数
def move_on_release(x, y):
    print(f"マウスが ({x}, {y}) で離されました。タートルを移動します。")
    my_turtle.goto(x, y)

# screen.onrelease() を使ってイベントハンドラを登録
# デフォルトでは左クリック(ボタン1)に反応します
screen.onrelease(move_on_release)

# イベントループを開始し、ウィンドウが閉じないようにする
turtle.done() 

解説

  1. turtle.Screen() で描画スクリーンを取得します。
  2. turtle.Turtle() でタートルを作成します。
  3. move_on_release(x, y) 関数は、マウスが離されたときの xy 座標を受け取ります。この関数内で my_turtle.goto(x, y) を呼び出すことで、タートルをその位置に移動させます。
  4. screen.onrelease(move_on_release) で、マウスボタンが離されたときに move_on_release 関数が呼び出されるように設定します。
  5. turtle.done() は、プログラムが終了せずにイベントを待ち続けるために必要です。

例2: ドットを描きながら線を引く(ドラッグ&ドロップ風)

この例では、マウスボタンを押している間はドットを描き、マウスボタンを離したら描画を停止します。これは onclick()onrelease() の両方を組み合わせることで実現できます。

import turtle

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.title("ドラッグ&ドロップ風描画")

drawer_turtle = turtle.Turtle()
drawer_turtle.shape("circle")
drawer_turtle.color("red")
drawer_turtle.shapesize(0.5) # ドットのサイズ
drawer_turtle.penup() # 最初はペンを上げておく
drawer_turtle.speed(0)

is_drawing = False # 描画中かどうかを管理するフラグ

# マウスボタンが押されたときに実行される関数
def start_drawing(x, y):
    global is_drawing
    is_drawing = True
    drawer_turtle.goto(x, y)
    drawer_turtle.pendown() # ペンを下ろして描画開始
    drawer_turtle.dot() # 最初のドットを打つ
    print(f"描画開始: ({x}, {y})")

# マウスボタンが離されたときに実行される関数
def stop_drawing(x, y):
    global is_drawing
    is_drawing = False
    drawer_turtle.penup() # ペンを上げて描画停止
    print(f"描画終了: ({x}, {y})")

# マウスがドラッグされたときに実行される関数(常にドットを打つ)
def draw_on_drag(x, y):
    if is_drawing:
        drawer_turtle.goto(x, y)
        drawer_turtle.dot()

# イベントハンドラを登録
screen.onclick(start_drawing) # クリックで描画開始
screen.onrelease(stop_drawing) # リリースで描画停止
screen.ondrag(draw_on_drag) # ドラッグ中はドットを打ち続ける

turtle.done()

解説

  1. is_drawing というブール値のフラグで、現在描画中であるかを管理します。
  2. screen.onclick(start_drawing): マウスボタンが押されたときに start_drawing が呼ばれ、is_drawingTrue にし、ペンを下ろします。
  3. screen.onrelease(stop_drawing): マウスボタンが離されたときに stop_drawing が呼ばれ、is_drawingFalse にし、ペンを上げます。
  4. screen.ondrag(draw_on_drag): マウスがドラッグされている(ボタンが押された状態で移動している)ときに draw_on_drag が呼ばれます。is_drawingTrue の場合のみ、現在の位置にドットを描き、タートルを移動させます。これにより、マウスをドラッグしている間に線(ドットの連なり)が描かれます。

例3: 右クリックを離したら色が変わる

特定のボタン(例: 右クリック)が離されたときに、画面の背景色を変更する例です。

import turtle
import random

screen = turtle.Screen()
screen.setup(width=500, height=300)
screen.title("右クリックで色変更")

colors = ["red", "green", "blue", "yellow", "purple", "orange"]

# 右クリックが離されたときに実行される関数
def change_background_color(x, y):
    new_color = random.choice(colors) # ランダムな色を選択
    screen.bgcolor(new_color) # 背景色を変更
    print(f"右クリックが離されました。背景色を {new_color} に変更しました。")

# screen.onrelease() を使って右クリック(btn=3)にイベントハンドラを登録
screen.onrelease(change_background_color, btn=3)

turtle.done()

解説

  1. random.choice(colors) を使って、定義された色のリストからランダムな色を選びます。
  2. screen.bgcolor(new_color) で、スクリーンの背景色を変更します。
  3. screen.onrelease(change_background_color, btn=3) のように btn=3 を指定することで、右クリックが離されたときにのみ change_background_color 関数が実行されるように設定します。

左クリックと右クリック、それぞれに異なる onrelease アクションを設定する例です。

import turtle

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.title("複数ボタンのリリースイベント")

# 左クリックが離されたときに実行される関数
def left_click_released(x, y):
    print(f"左クリックが ({x}, {y}) で離されました。")
    # ここに左クリック離れたときの処理を書く
    turtle.dot(20, "blue") # 青いドットを描く

# 右クリックが離されたときに実行される関数
def right_click_released(x, y):
    print(f"右クリックが ({x}, y}) で離されました。")
    # ここに右クリック離れたときの処理を書く
    turtle.dot(20, "red") # 赤いドットを描く

# 各ボタンにイベントハンドラを登録
screen.onrelease(left_click_released, btn=1)  # 左クリック
screen.onrelease(right_click_released, btn=3) # 右クリック

turtle.done()
  1. btn=1 を指定して左クリックのリリースイベントを、btn=3 を指定して右クリックのリリースイベントをそれぞれ別の関数にバインドしています。
  2. これにより、どのマウスボタンが離されたかによって異なる動作を実行できます。


turtle.onclick(): マウスボタンが「押された」瞬間に反応する

これは onrelease() と対をなす最も直接的な代替方法です。

  • turtle.onclick(): マウスボタンが押されたときに発火。
  • turtle.onrelease(): マウスボタンが離されたときに発火。

使い分けの例

  • onrelease() を使うべき場面:
    • ドラッグ&ドロップ操作の終了(ボタンを離した位置でオブジェクトを確定する)。
    • ボタンを押している間は何かを行い、離したときにその動作を終了する場合。
    • 「ボタンを離した」という意図的なアクションを捉えたい場合。
  • onclick() を使うべき場面:
    • ボタンを押した瞬間にアクションを開始したい場合(例: ドラッグ操作の開始、メニューの選択)。
    • ボタンを「クリックした」という明確なアクションを捉えたい場合。

コード例 (onclick の使用)

import turtle

screen = turtle.Screen()

def clicked_handler(x, y):
    print(f"マウスが ({x}, {y}) でクリック(押されました)!")
    turtle.dot(10, "green")

screen.onclick(clicked_handler) # onrelease の代わりに onclick を使用
turtle.done()

turtle.ondrag(): マウスボタンが押されたままドラッグされている間に反応する

ondrag() は、マウスボタンが押された状態でカーソルが移動している間、継続的にイベントを発生させたい場合に非常に有用です。これは onrelease() と組み合わせることで、より複雑なドラッグ&ドロップ動作を実装できます。

特徴

  • 引数として現在の x 座標と y 座標を受け取ります。
  • マウスボタンが押されたまま、カーソルが移動するたびに指定された関数が呼び出されます。

コード例 (onclick と onrelease と ondrag の組み合わせ)

これは以前の例でも示しましたが、再掲します。描画アプリケーションなどで非常に役立ちます。

import turtle

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.title("描画アプリ (ondrag併用)")

drawer_turtle = turtle.Turtle()
drawer_turtle.shape("circle")
drawer_turtle.color("red")
drawer_turtle.shapesize(0.5)
drawer_turtle.penup()
drawer_turtle.speed(0)

is_drawing = False

def start_drawing(x, y):
    global is_drawing
    is_drawing = True
    drawer_turtle.goto(x, y)
    drawer_turtle.pendown()
    drawer_turtle.dot()
    print(f"描画開始: ({x}, {y})")

def stop_drawing(x, y):
    global is_drawing
    is_drawing = False
    drawer_turtle.penup()
    print(f"描画終了: ({x}, {y})")

def draw_on_drag(x, y):
    if is_drawing:
        drawer_turtle.goto(x, y)
        drawer_turtle.dot()

screen.onclick(start_drawing)  # マウスダウンで描画開始
screen.onrelease(stop_drawing) # マウスアップで描画終了
screen.ondrag(draw_on_drag)   # ドラッグ中に描画を続ける

turtle.done()

turtle.listen() と turtle.onkey(), turtle.onkeypress(), turtle.onkeyrelease(): キーボードイベント

マウスイベントとは直接関係ありませんが、ユーザーインタラクションの代替手段としてキーボード入力があります。

  • screen.onkeyrelease(fun, key): 特定のキーが離されたときに発火。
  • screen.onkeypress(fun, key): 特定のキーが押されている間に発火(キーリピートあり)。
  • screen.onkey(fun, key): 特定のキーが押されて離されたときに発火(キーリピートなし)。
  • screen.listen(): イベント(マウス、キーボードなど)をリッスン(監視)するようスクリーンに指示します。

コード例 (キーボード入力)

import turtle

screen = turtle.Screen()
screen.setup(width=500, height=300)
screen.title("キーボードで操作")

my_turtle = turtle.Turtle()
my_turtle.shape("arrow")
my_turtle.color("purple")

def move_forward():
    my_turtle.forward(20)

def turn_left():
    my_turtle.left(30)

def turn_right():
    my_turtle.right(30)

# イベントをリッスン開始
screen.listen()

# キーボードイベントハンドラを登録
screen.onkey(move_forward, "Up")      # 上矢印キーが押されて離されたら前進
screen.onkey(turn_left, "Left")       # 左矢印キーが押されて離されたら左旋回
screen.onkey(turn_right, "Right")     # 右矢印キーが押されて離されたら右旋回

# キーを離したときに何かしたい場合(onkeyrelease の例)
def on_space_release():
    print("スペースキーが離されました!")
    my_turtle.stamp() # スタンプを押す

screen.onkeyrelease(on_space_release, "space")

turtle.done()

これはイベント駆動というよりは、ユーザーからの直接的な入力を受け取るための方法です。GUIのようなインタラクションを構築する際に役立ちます。

  • screen.numinput(title, prompt, default=None, minval=None, maxval=None): 数値入力ダイアログを表示し、ユーザーの数値入力を受け取ります。
  • screen.textinput(title, prompt): テキスト入力ダイアログを表示し、ユーザーの文字列入力を受け取ります。

コード例 (入力ダイアログ)

import turtle

screen = turtle.Screen()
screen.setup(width=400, height=200)
screen.title("入力ダイアログ")

def get_user_input():
    # テキスト入力を受け取る
    name = screen.textinput("名前を入力", "あなたの名前は何ですか?")
    if name:
        print(f"入力された名前: {name}")
        turtle.write(f"こんにちは、{name}!", align="center", font=("Arial", 16, "normal"))
    else:
        print("名前が入力されませんでした。")

    # 数値入力を受け取る
    age = screen.numinput("年齢を入力", "あなたの年齢は?", default=20, minval=0, maxval=120)
    if age is not None: # キャンセルされた場合はNoneが返る
        print(f"入力された年齢: {age}")
        # 追加の処理...
    else:
        print("年齢が入力されませんでした。")


# ボタンを押したら入力ダイアログを表示する例
# (onrelease の代わりに onclick を使用)
screen.onclick(get_user_input)

turtle.done()

turtle.onrelease() は、マウスボタンが離れた特定の瞬間のイベントを処理するのに最適です。しかし、アプリケーションの要件に応じて、以下のような代替手段や組み合わせを検討することで、よりリッチでインタラクティブなプログラムを作成できます。

  • 直接的なユーザー入力: screen.textinput(), screen.numinput()
  • キーボード入力: screen.listen(), screen.onkey(), screen.onkeypress(), screen.onkeyrelease()
  • マウスのドラッグ: turtle.ondrag()
  • マウスのクリック: turtle.onclick()