Python Turtleの塗りつぶしがうまくいかない?filling()でデバッグする方法

2025-06-06

turtle.filling()とは?

turtle.filling()は、turtleグラフィックスにおいて、現在図形が塗りつぶし中であるかどうかをチェックするためのメソッドです。このメソッドは引数を取らず、戻り値としてブール値(TrueまたはFalse)を返します。

  • Falseが返された場合:現在、塗りつぶしは行われていません。つまり、begin_fill()が呼び出されていないか、またはend_fill()によって塗りつぶしプロセスが既に完了しています。
  • Trueが返された場合:現在、begin_fill()が呼び出されており、図形の塗りつぶしプロセスが進行中です。

使い方

turtle.filling()は、主にプログラムのロジックの中で、現在の塗りつぶし状態に応じて異なる処理を行いたい場合に使用します。


import turtle

t = turtle.Turtle()
t.speed(1) # 少し遅くして動きを確認

print(f"初期状態での塗りつぶし中か?: {t.filling()}") # Falseが出力されるはず

t.begin_fill() # 塗りつぶしを開始
print(f"begin_fill()呼び出し後、塗りつぶし中か?: {t.filling()}") # Trueが出力されるはず

t.circle(50) # 円を描画(この時点ではまだ塗りつぶされない)

t.end_fill() # 塗りつぶしを終了し、図形が描画・塗りつぶされる
print(f"end_fill()呼び出し後、塗りつぶし中か?: {t.filling()}") # Falseが出力されるはず

turtle.done()
  1. 初期状態では、t.filling()Falseを返します。
  2. t.begin_fill()を呼び出すと、塗りつぶしモードに入り、t.filling()Trueを返します。この段階で描かれる線は、後で指定された色で塗りつぶされる領域の境界線となります。
  3. t.end_fill()を呼び出すと、begin_fill()からend_fill()までの間に描かれた図形が指定された塗りつぶし色で閉じられ、塗りつぶされます。その後、t.filling()は再びFalseを返します。
  • ユーザーインターフェース
    グラフィカルなアプリケーションで、塗りつぶし状態を示すUI要素(例:塗りつぶしボタンの状態変更)と同期させる場合に使うことも考えられます。
  • 条件分岐
    例えば、「もし現在塗りつぶし中であれば、別の描画処理をスキップする」といった、プログラムのフローを制御するために使用できます。
  • デバッグ
    塗りつぶし処理が正しく行われているかを確認する際に役立ちます。


turtle.filling()自体が直接エラーを引き起こすことは稀ですが、begin_fill()end_fill()という、塗りつぶし機能の主要なメソッドと連携する際に問題が発生することがほとんどです。

塗りつぶしが全く行われない

  • トラブルシューティング
    • コード内でt.begin_fill()t.end_fill()が適切に呼び出されていることを確認してください。
    • これらの呼び出しが、実際に塗りつぶしたい図形を描くコードを挟むように配置されていることを確認してください。
    • 重要
      begin_fill()end_fill()の間で描かれるパスが閉じられた図形を形成している必要があります。閉じられていない場合でも塗りつぶしは行われますが、期待通りの形にならないことがあります。タートルがbegin_fill()からend_fill()までに移動した経路の始点と終点が自動的に直線で結ばれて塗りつぶされます。
  • turtle.filling()での確認
    • begin_fill()を呼び出した直後にprint(t.filling())としてTrueが返ってくるか確認してください。
    • end_fill()を呼び出した直後にprint(t.filling())としてFalseが返ってくるか確認してください。
    • もしbegin_fill()を呼び出してもTrueにならない、またはend_fill()を呼び出してもFalseにならない場合、begin_fill()end_fill()の呼び出し自体に問題があります(例:タイプミス、関数として呼び出されていないなど)。
  • 考えられる原因
    begin_fill()end_fill()がペアになっていない、または呼び出されていない。

塗りつぶし色が期待と異なる

  • トラブルシューティング
    • t.fillcolor("red")のように、begin_fill()を呼び出す前にt.fillcolor()を使って色を設定していることを確認してください。
    • 色のスペルが正しいか(例: "red", "blue", "green" またはRGB値 (r, g, b))確認してください。
    • ペン色(pencolor())と塗りつぶし色(fillcolor())を混同していないか確認してください。
  • turtle.filling()での確認
    turtle.filling()は色自体とは関係ありませんが、塗りつぶしプロセスがアクティブであるかどうかの確認には役立ちます。
  • 考えられる原因
    fillcolor()の設定が間違っているか、begin_fill()の前に設定されていない。
  • トラブルシューティング
    • 各図形ごとにbegin_fill()end_fill()のペアを独立して使用してください。
    • 例:
      t.begin_fill()
      t.circle(30) # 1つ目の図形
      t.end_fill()
      
      t.penup()
      t.goto(100, 0)
      t.pendown()
      
      t.begin_fill()
      t.square(40) # 2つ目の図形
      t.end_fill()
      
    • 上記のように、一つの図形を描画・塗りつぶしたら、必ずend_fill()でそのセッションを終了し、次の図形を描画する前に再度begin_fill()を開始するようにします。
  • turtle.filling()での確認
    塗りつぶしプロセスが意図せず長時間Trueのままになっていないか、print(t.filling())で確認できます。
  • 考えられる原因
    begin_fill()end_fill()のスコープが広すぎる、または連続して呼び出されている。

描画速度が遅い、または画面がフリーズする

  • turtle.filling()での確認
    直接的な原因ではありませんが、塗りつぶし処理が頻繁に行われる状況でこの問題が起きやすいです。
  • 考えられる原因
    非常に複雑な図形を塗りつぶそうとしている、または非常に多くの小さな図形をループで描画・塗りつぶししている。


turtle.filling()は、主に塗りつぶし処理がアクティブであるかどうかの状態を確認するために使用されます。ここでは、いくつかの異なるシナリオでその使い方を見ていきましょう。

例1: 塗りつぶし状態の確認と表示

この例では、begin_fill()end_fill()の前後でturtle.filling()の状態をprintで出力し、その変化を確認します。

import turtle

# タートルオブジェクトを作成
t = turtle.Turtle()
t.speed(3) # 描画速度を設定(遅め)
t.pencolor("blue") # ペンの色
t.fillcolor("lightblue") # 塗りつぶしの色

# 1. 塗りつぶし開始前の状態
print(f"1. begin_fill()前: 塗りつぶし中か? {t.filling()}") # False が出力されるはず

# 2. 塗りつぶし開始
t.begin_fill()
print(f"2. begin_fill()後: 塗りつぶし中か? {t.filling()}") # True が出力されるはず

# 3. 図形の描画(四角形)
for _ in range(4):
    t.forward(100)
    t.left(90)

# 4. 塗りつぶし終了
t.end_fill()
print(f"4. end_fill()後: 塗りつぶし中か? {t.filling()}") # False が出力されるはず

# 画面を閉じるまで待機
turtle.done()

解説

  • end_fill()が呼び出され、塗りつぶしが完了すると、t.filling()は再びFalseに戻ります。
  • このTrueの間で描画された線が、後にend_fill()で閉じられ、指定された色で塗りつぶされます。
  • begin_fill()を呼び出すと、タートルは「これから塗りつぶす図形の境界線を描く」モードに入り、t.filling()Trueになります。
  • begin_fill()を呼び出す前はt.filling()Falseです。

例2: 条件分岐でのturtle.filling()の利用

この例では、turtle.filling()を使って、現在の塗りつぶし状態に基づいて異なる処理を行う方法を示します。例えば、塗りつぶし中でなければペンを上げて移動する、といった制御が可能です。

import turtle

t = turtle.Turtle()
t.speed(0) # 最速
t.pencolor("black")
t.fillcolor("gold")

def draw_and_fill_shape():
    # もし現在塗りつぶし中でなければ、開始する
    if not t.filling(): # t.filling() == False と同じ意味
        print("塗りつぶしを開始します。")
        t.begin_fill()
    else:
        print("すでに塗りつぶし中です。")

    t.circle(50) # 円を描画

    # 塗りつぶし中であれば、終了する
    if t.filling(): # t.filling() == True と同じ意味
        print("塗りつぶしを終了します。")
        t.end_fill()
    else:
        print("塗りつぶしは行われていませんでした。")

# 1回目:塗りつぶしなしで呼び出し
t.penup()
t.goto(-100, 0)
t.pendown()
draw_and_fill_shape() # この呼び出しで円が描かれ、塗りつぶされる

# 2回目:塗りつぶし途中で呼び出し(通常はこのような使い方はしないが、デモ目的)
# 意図的に begin_fill() を手動で呼び出す
t.penup()
t.goto(100, 0)
t.pendown()
t.begin_fill() # ここで塗りつぶしを強制的に開始

print("\n--- 2回目の呼び出し(手動でbegin_fill後) ---")
draw_and_fill_shape() # この呼び出しでは、if not t.filling() が False になる

turtle.done()

解説

  • 2回目の関数呼び出しでは、draw_and_fill_shape()の前にt.begin_fill()を直接呼び出しているため、関数内のif not t.filling():の条件がFalseとなり、begin_fill()は再度呼び出されません。これにより、関数が現在の塗りつぶし状態を認識していることがわかります。
  • 同様に、描画後にif t.filling():で塗りつぶし中であればend_fill()を呼び出すようにしています。
  • draw_and_fill_shape()関数内で、if not t.filling():を使って、もし塗りつぶし中でなければbegin_fill()を呼び出すようにしています。

例3: 塗りつぶし中の線と、そうでない線の区別

この例では、turtle.filling()の状態に応じてペンの色を変えることで、塗りつぶし中の線とそうでない線を視覚的に区別します。

import turtle

t = turtle.Turtle()
t.speed(3)
t.pencolor("black") # 通常の線の色
t.fillcolor("lightgreen") # 塗りつぶしの色

# 最初の四角形(塗りつぶしなし)
print(f"四角形Aの描画前: 塗りつぶし中? {t.filling()}")
if not t.filling():
    t.pencolor("gray") # 塗りつぶし中でない線はグレーに
for _ in range(4):
    t.forward(50)
    t.left(90)
t.pencolor("black") # 色を元に戻す
print(f"四角形Aの描画後: 塗りつぶし中? {t.filling()}")

t.penup()
t.goto(100, 0)
t.pendown()

# 塗りつぶし付きの円
print(f"\n円の描画前: 塗りつぶし中? {t.filling()}")
t.begin_fill()
print(f"円の描画中: 塗りつぶし中? {t.filling()}") # True になっている
if t.filling():
    t.pencolor("red") # 塗りつぶし中の線は赤に
t.circle(50)
t.pencolor("black") # 色を元に戻す
t.end_fill()
print(f"円の描画後: 塗りつぶし中? {t.filling()}") # False になっている

turtle.done()
  • 円を描く際にt.begin_fill()を呼び出すと、t.filling()Trueになるため、その間はペンの色がredに変わります。end_fill()で塗りつぶしが完了すると、t.filling()Falseに戻り、ペン色も元に戻します。
  • 最初の四角形を描く前はt.filling()Falseなので、ペンの色が一時的にgrayに変わります。


Therefore, "alternative methods for programming related to turtle.filling()" aren't about replacing turtle.filling() itself, but rather about:

  1. How you control the filling process (which turtle.filling() reports on). The alternatives here are mainly about how you initiate and conclude the fill.
  2. How you might track the filling state yourself if you didn't want to use turtle.filling() directly. This involves using your own variables to manage the state.

Pythonのturtleモジュールにおけるturtle.filling()に関連するプログラミングの「代替方法」についてご説明します。

turtle.filling()は、基本的にタートルが現在塗りつぶし操作中であるかどうかという状態を問い合わせるためのメソッドです。これは何らかの「アクション」を実行するものではなく、現在の「状態を報告する」ものです。

したがって、「turtle.filling()に関連するプログラミングの代替方法」とは、turtle.filling()そのものを置き換えるというよりも、以下の2つの側面について考えることになります。

  1. 塗りつぶしプロセスをどのように「制御」するか(turtle.filling()が報告する対象)。 ここでの代替は、主に塗りつぶしを開始・終了する方法に関するものです。
  2. turtle.filling()を直接使わずに、自分で塗りつぶしの状態をどのように「追跡」するか。 これは、独自の変数を使って状態を管理する方法を指します。

塗りつぶしプロセスを制御する代替方法(turtle.filling()が報告する内容)

turtle.filling()Trueを返すのはturtle.begin_fill()が呼び出された後で、Falseを返すのはturtle.end_fill()が呼び出された後です。つまり、塗りつぶしプロセス自体を制御する主要な方法は、begin_fill()end_fill()を正しく使うこと以外に「代替」はありません。

しかし、これらのメソッドを使う際のプログラミングパターンにはいくつか考え方があります。

  • 代替というよりは「応用」
    例えば、特定の関数内で図形を描画・塗りつぶす場合、その関数が責任を持ってbegin_fill()end_fill()をペアで呼び出すように設計することが重要です。

    import turtle
    
    def draw_filled_square(size, color):
        t = turtle.Turtle() # 関数内で新しいタートルを作成(または既存のタートルを引数で渡す)
        t.speed(0)
        t.fillcolor(color)
        t.begin_fill()
        for _ in range(4):
            t.forward(size)
            t.left(90)
        t.end_fill()
    
    draw_filled_square(100, "green")
    draw_filled_square(50, "red") # 新しいタートルなので重ならない
    
    turtle.done()
    

    この場合、turtle.filling()は各draw_filled_square呼び出しの内部でのみTrueとなり、関数が終了すればFalseに戻ります。ここでの「代替」とは、turtle.filling()を外部から直接操作するのではなく、塗りつぶしロジックを関数内にカプセル化するという設計のアプローチです。

  • 一般的な使用法

    import turtle
    
    t = turtle.Turtle()
    t.fillcolor("blue")
    
    t.begin_fill()      # 塗りつぶし開始
    t.circle(50)        # 図形を描画
    t.end_fill()        # 塗りつぶし終了・確定
    
    turtle.done()
    

    これが標準的で推奨される方法であり、turtle.filling()がこのプロセスの状態を正確に報告します。

turtle.filling()はタートルの内部状態を問い合わせる公式な方法ですが、もし何らかの理由でこれを使いたくない、あるいは独自のロジックで状態を管理したい場合、ブール型の変数を使って自ら状態を管理することができます。

これはturtle.filling()の「代替」というよりも、「turtle.filling()を使わずに同じ情報を得る」方法です。

import turtle

t = turtle.Turtle()
t.fillcolor("purple")

# 塗りつぶし状態を追跡するための独自の変数
_is_filling_custom = False

def my_begin_fill():
    global _is_filling_custom # グローバル変数を変更する
    if not _is_filling_custom: # 既に開始されていなければ
        t.begin_fill()
        _is_filling_custom = True
        print(f"my_begin_fill: 塗りつぶし開始。_is_filling_custom: {_is_filling_custom}")
    else:
        print("my_begin_fill: 既に塗りつぶし中です。")

def my_end_fill():
    global _is_filling_custom
    if _is_filling_custom: # 塗りつぶし中であれば
        t.end_fill()
        _is_filling_custom = False
        print(f"my_end_fill: 塗りつぶし終了。_is_filling_custom: {_is_filling_custom}")
    else:
        print("my_end_fill: 塗りつぶしは行われていませんでした。")

# 独自の変数を使って状態を確認する関数
def is_filling_custom():
    return _is_filling_custom

# --- 使用例 ---

print(f"初期状態: {is_filling_custom()}") # False

my_begin_fill()
t.circle(50)
print(f"円描画中: {is_filling_custom()}") # True

my_end_fill()
print(f"塗りつぶし終了後: {is_filling_custom()}") # False

# 2回連続でmy_begin_fillを呼ぶとどうなるか
my_begin_fill()
my_begin_fill() # 既にTrueなので、再度begin_fillは呼ばれない
t.forward(100)
my_end_fill()

turtle.done()

解説

  • is_filling_custom()関数は、このカスタム変数の現在の値を返します。
  • my_begin_fill()my_end_fill()というラッパー関数を作成し、その中で実際のt.begin_fill()t.end_fill()を呼び出すとともに、_is_filling_custom変数を更新します。
  • _is_filling_customというブール型のグローバル変数を定義し、塗りつぶしが開始されたらTrueに、終了したらFalseに設定します。
  • 欠点
    • turtle.filling()という既存の公式メソッドがあるため、ほとんどの場合で冗長であり、バグの原因になりやすいです。タートル内部の実際の状態と、カスタム変数の状態が同期しなくなるリスクがあります。
    • turtle.filling()はC言語で実装されており、Python側で独自の変数を持つよりも効率的です。
  • 利点
    • turtleオブジェクトに直接アクセスできないが、その状態を模倣して追跡したい場合に役立つ可能性があります(稀なケース)。
    • 独自のロジックを状態管理に組み込みたい場合に柔軟性があります。