2013-04-17 20 views
5

python 3プログラムを終了すると、コンソールに奇妙な例外が発生します。_tkinter.TclError:無効なコマンド名 ".4302957584"

ザ・Pythonの3コード:

/Library/Frameworks/Python.framework/Versions/3.3/bin/python3 "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py" 
Traceback (most recent call last): 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 446, in <module> 
    BounceBalls() 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 407, in __init__ 
    self.animate() 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 428, in animate 
    self.canvas.delete("ball") 
    File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/__init__.py", line 2344, in delete 
    self.tk.call((self._w, 'delete') + args) 
_tkinter.TclError: invalid command name ".4302957584" 

Process finished with exit code 1 

なぜこれらの例外が発生している:

from tkinter import * 
from random import randint 

# Return a random color string in the form of #RRGGBB 
def getRandomColor(): 
    color = "#" 
    for j in range(6): 
     color += toHexChar(randint(0, 15)) # Add a random digit 
    return color 

# Convert an integer to a single hex digit in a character 
def toHexChar(hexValue): 
    if 0 <= hexValue <= 9: 
     return chr(hexValue + ord('0')) 
    else: # 10 <= hexValue <= 15 
     return chr(hexValue - 10 + ord('A')) 

# Define a Ball class 
class Ball: 
    def __init__(self): 
     self.x = 0 # Starting center position 
     self.y = 0 
     self.dx = 2 # Move right by default 
     self.dy = 2 # Move down by default 
     self.radius = 3 
     self.color = getRandomColor() 

class BounceBalls: 
    def __init__(self): 
     self.ballList = [] # Create a list for balls 

     window = Tk() 
     window.title("Bouncing Balls") 

     ### Create Canvas ### 
     self.width = 350 
     self.height = 150 
     self.canvas = Canvas(window, bg = "white", width = self.width, height = self.height) 
     self.canvas.pack() 


     ### Create Buttons ### 
     frame = Frame(window) 
     frame.pack() 

     btStop = Button(frame, text = "Stop", command = self.stop) 
     btStop.pack(side = LEFT) 

     btResume = Button(frame, text = "Resume", command = self.resume) 
     btResume.pack(side = LEFT) 

     btAdd = Button(frame, text = "Add", command = self.add) 
     btAdd.pack(side = LEFT) 

     btRemove = Button(frame, text = "Remove", command = self.remove) 
     btRemove.pack(side = LEFT) 

     self.sleepTime = 20 
     self.isStopped = False 
     self.animate() 

     window.mainloop() 

    def stop(self): # Stop animation 
     self.isStopped = True 

    def resume(self): 
     self.isStopped = False 
     self.animate() 

    def add(self): # Add a new ball 
     self.ballList.append(Ball()) 

    def remove(self): 
     self.ballList.pop() 

    def animate(self): 
     while not self.isStopped: 
      self.canvas.after(self.sleepTime) 
      self.canvas.update() 
      self.canvas.delete("ball") 

      for ball in self.ballList: 
       self.redisplayBall(ball) 

    def redisplayBall(self, ball): 
     if ball.x > self.width or ball.x < 0: 
      ball.dx = -ball.dx 

     if ball.y > self.height or ball.y < 0: 
      ball.dy = -ball.dy 

     ball.x += ball.dx 
     ball.y += ball.dy 
     self.canvas.create_oval(ball.x - ball.radius, ball.y - ball.radius, \ 
           ball.x + ball.radius, ball.y + ball.radius, \ 
           fill = ball.color, tags = "ball") 

BounceBalls() 

ここで完全なトレースバックですか?

+0

このコードはこの本で入手できましたか?これはTkinterでアニメーションを行うには間違った方法であり、問​​題に寄与しています。 Tkinterでアニメーションを作成する方法については、このWebサイトを検索したいかもしれません。 –

+0

はい、私はしました。この本にはサンプルコードが表示されており、コードを入力するだけです。 – narzero

+0

これは残念です。それは悪い例です。 : - \ –

答えて

3

メインアプリケーションループwindow.mainloopは、stopボタンを押さないと実行されません。あなたの問題の原因です。アニメーションループを書き直します。

def __init__(self): 
    ... 
    self.sleepTime = 20 
    self.isStopped = False 
    self.window = window 
    self.window.after(self.sleepTime, self.animate) 
    window.mainloop() 
    ... 

def animate(self): 
    if not self.isStopped: 
     self.canvas.update() 
     self.canvas.delete("ball") 

     for ball in self.ballList: 
      self.redisplayBall(ball) 
     self.window.after(self.sleepTime, self.animate) 
+4

この例では、 'update'の呼び出しは全く必要ありません。 –

3

プログラムを終了すると、ウィンドウが破棄されます。この破壊は、アプリケーションが終了したことをイベントループが通知した後に発生します。あなたのコードが構造化されている方法は、self.update()と呼ぶときに起こります。その呼び出しの直後、およびウィジェットが破棄された後、あなたはself.canvas.delete("ball")に電話しています。前のステートメントでウィジェットが破棄されたので、エラーが発生します。

Tkinterがtcl/tkインタプリタを囲む単なるラッパーであるということは、エラーがあまりにも謎めいている理由です。 Tkウィジェットには、ドットといくつかの文字が続き、ウィジェット名もtclコマンドです。キャンバスのdeleteメソッドを呼び出すと、Tkinterはキャンバスリファレンスを内部のtkウィジェット名/ tclコマンドに変換します。ウィジェットは破壊されているので、tkはそれを既知のコマンドとして認識せず、エラーをスローします。

解決策では、アニメーションロジックをやり直す必要があります。独自のアニメーションループを持つべきではありません。代わりに、アニメーションループとしてTkinterイベントループ(mainloop())を使用する必要があります。このサイトにいくつかの例があります(例:https://stackoverflow.com/a/11505034/7432

関連する問題