2017-10-29 7 views
2

私は楕円形の谷に画面を移動これは本当に簡単なコードを書いた:のTkinter:最適化キャンバスオブジェクトの動き

from tkinter import * 

""" GLOBAL VARS """ 
H, W = 400, 600 # default height/width 
DELAY = 30 # frame rate in milliseconds 
R = 20 # radius of the ball 


class App: 
    def __init__(self, parent): 
     """ app init """ 
     self.root = parent 
     self.canvas = Canvas(self.root, bg="white", height=H, width=W) 
     self.canvas.pack() 

     self.pos = [W/2, H/2] # starting position 
     self.speed = [2, 2] # x/y speed 

     self.canvas.create_oval(self.pos[0] - 20, self.pos[1] - 20, self.pos[0] + 20, self.pos[1] + 20, fill="blue") 

     self.loop() 


    def loop(self): 
     """ main loop """ 
     coords = self.canvas.coords(1)[:2] # actual oval coordinates 

     if not 0 < coords[0] < W - 20: # the oval bounce off the window 
      self.speed[0] *= -1 
     if not 0 < coords[1] < H - 20: 
      self.speed[1] *= -1 

     self.canvas.move(1, *self.speed) 

     self.root.after(DELAY, self.loop) 


""" GUI SETUP """ 
root = Tk() 
App(root) 
root.mainloop() 

問題は、私は、フレームレートを向上しようとすると、楕円形の半分が消滅は、(私が試したということですいくつかのスクリーンショットを撮ることができますが、私がそうすると、1つのフレームでアプリがフリーズし、スクリーンショットで楕円が正しく表示されます。上のコードを実行することで自分自身を試すことができます。

私の質問は:モーションを最適化する方法があるのか​​、それともTkinterが高いfpsを処理できないという事実を受け入れる必要がありますか?

+0

上記のコードは私にとって完璧に機能します。どのプラットフォームを実行していますか? –

+0

@BryanOakley私はLenovo IdeapadでWindows 10を使用しています。 –

答えて

2

これは私がアンダー文書であると感じているものですTkinter performance issue。キャンバス上で何を更新するかを検出すると、更新する必要があるものはすべてで、楕円形の場合はキャンバスのその部分だけを更新します(最適化のために)。理由)。

しかし、楕円をキャンバスにすばやく移動させると、カンバスのセクションが更新されます。これは、楕円の一部が切り取られることを意味します。

これはDamage/Repair modelです。

私の意見では、これを処理して修正する最も簡単な方法は、更新したいものの周りに大きな(目に見えない)オブジェクトを作成することです。つまり、Tkinterは大きなオブジェクトを検出し、その周りのウィジェット(キャンバス)の部分を更新します。トリックは、新しい更新されたセクションにあなたが表示したいもの、楕円を包含させることです。

tag systemで大きな目に見えないオブジェクトと楕円の両方を簡単に移動できます。

tag"circle"をあなたの楕円に追加して、同じ楕円形の同じ楕円を作成できますが、楕円全体をカバーする座標になります。 fill=""outline=""を指定して、新しいオブジェクトが表示されないようにすることも重要です。

これは次のようになります。

self.canvas.create_oval(self.pos[0] - 20, self.pos[1] - 20, 
          self.pos[0] + 20, self.pos[1] + 20, fill="blue", tag="circle") 
    self.canvas.create_oval(self.pos[0] - 40, self.pos[1] - 40, self.pos[0] + 40, 
          self.pos[1] + 40, fill="", outline="", tag="circle") 

最初に作成した楕円形のタグで今、あなたの現在の楕円形であり、第二の楕円形が見えない、大きなものです。

あなたは楕円を移動すると、代わりに(あなたが最初にそれを作成するため、現時点ではあなたの楕円形のIDです)1を移動する、あなたは"circle"を移動することができます。

self.canvas.move("circle", *self.speed) 

あなたはこれを実装した後は、お使いの楕円はカットオフを示すべきではない。それでもカットオフが見える場合は、目に見えない楕円のサイズを大きくすることができます。 40ではなく、60のオフセットを使用します。

+0

よく文書化された回答をありがとう!それはまだ1000fpsで40の半径の楕円でいくつかの問題を抱えていましたが、サイズを今すぐ完全に動作させる! –