2016-12-15 2 views
0

내 질문에 어리 석거나 까다로운 질문인지 모르겠습니다.Tkinter Canvas : 움직이는 물체의 축척

그래서 Tkinter와 Canvas를 사용하여이 게시물 Move and zoom a tkinter canvas with mouse 덕분에 완벽하게 작동하는 스크롤/확대/축소 기능을 구현하는 데 성공했습니다. 또한 창 크기가 문제없이 변경되면 캔바스 크기의 크기를 조정하는 바인딩을 추가합니다.

coordsafter을 사용하면 object으로 이동할 수 있습니다.

모든 것을 결합하려고 할 때 문제가 발생했습니다.이

  • 확대, 이동 및 스크롤이 확인 : 코드는 울부 짖는 소리 창에 문제 (python 2.7, 저작물을 복제
  • 작동하지 않습니다

    • 이동 및 스크롤 : 없음 문제
    • 스크롤 및 확대를). 내가 볼 수있는 문제는 스케일링에서 왔는데, 어쩌면 객체의 coords이 변경되어 캔버스 크기 조정을 유도 한 다음 스케일을 사용하지 않도록 설정할 수 있습니까? 그렇다면이 문제를 해결하는 데 도움이 필요합니다. 그렇지 않은 경우 문제를 발견하는 데 도움이 필요합니다 ...

      self.master.after(50, self.Display)을 제거/비활성화하면 더 이상 움직이지 않습니다.

      import Tkinter as tk 
      import math 
      
      class Example: 
          def __init__ (self, master): 
           self.master = master 
           self.interval = 0 
           self.SizeX, self.SizeY = master.winfo_width(), master.winfo_height() 
           #Canvas Frame 
           self.SystemCanvasFrame = tk.Frame(master, bg='black') 
           self.SystemCanvasFrame.grid(row=0, column=0) 
      
           #Canvas 
           self.SystemCanvas = tk.Canvas(self.SystemCanvasFrame, width=int(self.SizeX*0.75)-20, height=self.SizeY-20, bg="black") 
           self.SystemCanvas.focus_set() 
           self.xsb = tk.Scrollbar(self.SystemCanvasFrame, orient="horizontal", command=self.SystemCanvas.xview) 
           self.ysb = tk.Scrollbar(self.SystemCanvasFrame, orient="vertical", command=self.SystemCanvas.yview) 
           self.SystemCanvas.configure(scrollregion=(-500,-500,500,500)) 
           self.SystemCanvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set) 
           #add the canvas with scroll bar in grid format 
           self.xsb.grid(row=1, column=0, sticky="ew") 
           self.ysb.grid(row=0, column=1, sticky="ns") 
           self.SystemCanvas.grid(row=0, column=0, sticky="nsew") 
      
           # This is what enables using the mouse to slide the window: 
           self.SystemCanvas.bind("<ButtonPress-1>", self.move_start) 
           self.SystemCanvas.bind("<B1-Motion>", self.move_move) 
           #windows scroll 
           self.SystemCanvas.bind("<MouseWheel>",self.zoomer)   
           #resize the main window 
           self.master.bind('<Configure>', self.UpdateCanvasSize) 
      
           #Create Objects 
           self.Size = 5 #object Size 
           x0 = 0 
           y0 = 0 
           x1 = self.Size 
           y1 = self.Size 
           self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='green', outline='green', width=3, tags='Green') 
           self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='red', outline='red', width=3, tags='Red') 
           self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='yellow', outline='yellow', width=1, tags='Yellow') 
      
           self.Display() 
      
          def Display(self): 
           self.interval += 0.5 #speed parameter 
           GreenPos = self.UpdatePosition(0.1*self.interval, (0,0), 50) 
           RedPos = self.UpdatePosition(0.02*self.interval+180, (0,0), 200) 
           YellowPos = self.UpdatePosition(0.3*self.interval, RedPos, 10) 
      
           self.MoveObject('Green', GreenPos) 
           self.MoveObject('Red', RedPos) 
           self.MoveObject('Yellow', YellowPos) 
      
           self.master.after(50, self.Display) #Disable to zoom 
      
          def MoveObject (self, Obj, pos): #only move object that are in the field of view 
           """Move Obj to the given position (tuple - xy)""" 
           ID = self.SystemCanvas.find_withtag(Obj)  
           #Convert the Center of the object to the coo need for tk 
           x0 = pos[0] - self.Size/2.0 #radius of the circle 
           y0 = pos[1] - self.Size/2.0 
           x1 = pos[0] + self.Size/2.0 
           y1 = pos[1] + self.Size/2.0 
           self.SystemCanvas.coords(ID, x0,y0,x1,y1) 
      
          def UpdatePosition(self, angle, center, distance): 
           """Calculate next object position around the Center at the Distance and speed determine by Angle (in Radian) - Center of the object""" 
           h = center[0] 
           k = center[1] 
           radius = distance 
           Rad = angle 
           x = h+radius*math.cos(Rad) 
           y = k+radius*math.sin(Rad) 
           return (x, y) 
      
          def UpdateCanvasSize(self, event): 
           """Permit to resize the canvas to the window""" 
           self.SizeX, self.SizeY = self.master.winfo_width(), self.master.winfo_height() 
           self.SystemCanvas.config(width=int(self.SizeX*0.75)-20, height=self.SizeY-20) 
      
          def move_start(self, event): 
           """Detect the beginning of the move""" 
           self.SystemCanvas.scan_mark(event.x, event.y) 
           self.SystemCanvas.focus_set() #security, set the focus on the Canvas 
      
          def move_move(self, event): 
           """Detect the move of the mouse""" 
           self.SystemCanvas.scan_dragto(event.x, event.y, gain=1) 
      
          def zoomer(self,event): 
           """Detect the zoom action by the mouse. Zoom on the mouse focus""" 
           true_x = self.SystemCanvas.canvasx(event.x) 
           true_y = self.SystemCanvas.canvasy(event.y) 
           if (event.delta > 0): 
            self.SystemCanvas.scale("all", true_x, true_y, 1.2, 1.2) 
           elif (event.delta < 0): 
            self.SystemCanvas.scale("all", true_x, true_y, 0.8, 0.8) 
           self.SystemCanvas.configure(scrollregion = self.SystemCanvas.bbox("all")) 
      
      if __name__ == '__main__': 
          root = tk.Tk() 
          root.geometry('1125x750') 
          app = Example(root) 
          root.mainloop() 
      

    답변

    1

    저는 Tkinter를 처음 사용 했으므로 이것이 가장 우아한 해결책은 아니지만 문제 해결 방법에 대한 아이디어를 얻으시기 바랍니다.

    zoomer 메서드는 좌표를 조정하지만 MoveObject 또는 UpdatePosition을 호출 할 때마다 좌표가 재설정됩니다. 스케일 팩터를 추적하는 코드 인 self.scale과 스케일 인자에 따라 주어진 좌표를 스케일하는 update_coord 메소드를 추가했습니다. 마지막으로, 나는 을 MoveObjectUpdatePosition 방법으로 호출했다.

    다음은 작동 코드입니다.

    import Tkinter as tk 
    import math 
    
    class Example: 
        def __init__ (self, master): 
    
         self.scale = 1 #Added 
    
         self.master = master 
         self.interval = 0 
         self.SizeX, self.SizeY = master.winfo_width(), master.winfo_height() 
         #Canvas Frame 
         self.SystemCanvasFrame = tk.Frame(master, bg='black') 
         self.SystemCanvasFrame.grid(row=0, column=0) 
    
         #Canvas 
         self.SystemCanvas = tk.Canvas(self.SystemCanvasFrame, width=int(self.SizeX*0.75)-20, height=self.SizeY-20, bg="black") 
         self.SystemCanvas.focus_set() 
         self.xsb = tk.Scrollbar(self.SystemCanvasFrame, orient="horizontal", command=self.SystemCanvas.xview) 
         self.ysb = tk.Scrollbar(self.SystemCanvasFrame, orient="vertical", command=self.SystemCanvas.yview) 
         self.SystemCanvas.configure(scrollregion=(-500,-500,500,500)) 
         self.SystemCanvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set) 
         #add the canvas with scroll bar in grid format 
         self.xsb.grid(row=1, column=0, sticky="ew") 
         self.ysb.grid(row=0, column=1, sticky="ns") 
         self.SystemCanvas.grid(row=0, column=0, sticky="nsew") 
    
         # This is what enables using the mouse to slide the window: 
         self.SystemCanvas.bind("<ButtonPress-1>", self.move_start) 
         self.SystemCanvas.bind("<B1-Motion>", self.move_move) 
         #windows scroll 
         self.SystemCanvas.bind("<MouseWheel>",self.zoomer)   
         #resize the main window 
         self.master.bind('<Configure>', self.UpdateCanvasSize) 
    
         #Create Objects 
         self.Size = 5 #object Size 
         x0 = 0 
         y0 = 0 
         x1 = self.Size 
         y1 = self.Size 
         self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='green', outline='green', width=3, tags='Green') 
         self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='red', outline='red', width=3, tags='Red') 
         self.SystemCanvas.create_oval(x0,y0,x1,y1, fill='yellow', outline='yellow', width=1, tags='Yellow') 
    
         self.Display() 
    
    
        #**Added Method 
        def update_coord(self, coord): 
         """Calculate the scaled cordinate for a given cordinate based on the zoomer scale factor""" 
         new_coord = [coord_i * self.scale for coord_i in coord] 
         return new_coord 
    
    
        def Display(self): 
         self.interval += 0.5 #speed parameter 
         GreenPos = self.UpdatePosition(0.1*self.interval, (0,0), 50) 
         RedPos = self.UpdatePosition(0.02*self.interval+180, (0,0), 200) 
         YellowPos = self.UpdatePosition(0.3*self.interval, RedPos, 10) 
    
         self.MoveObject('Green', GreenPos) 
         self.MoveObject('Red', RedPos) 
         self.MoveObject('Yellow', YellowPos) 
    
    
         self.master.after(1, self.Display) #Disable to zoom 
    
        def MoveObject (self, Obj, pos): #only move object that are in the field of view 
         """Move Obj to the given position (tuple - xy)""" 
         ID = self.SystemCanvas.find_withtag(Obj)  
         #Convert the Center of the object to the coo need for tk 
         x0 = pos[0] - self.Size/2.0 #radius of the circle 
         y0 = pos[1] - self.Size/2.0 
         x1 = pos[0] + self.Size/2.0 
         y1 = pos[1] + self.Size/2.0 
         c_0 = self.update_coord([x0, y0]) #Added 
         c_1 = self.update_coord([x1, y1]) #Added 
         self.SystemCanvas.coords(ID, c_0[0], c_0[1], c_1[0], c_1[1]) #Added/Edited 
    
        def UpdatePosition(self, angle, center, distance): 
         """Calculate next object position around the Center at the Distance and speed determine by Angle (in Radian) - Center of the object""" 
         h = center[0] 
         k = center[1] 
         radius = distance 
         Rad = angle 
         x = h+radius*math.cos(Rad) 
         y = k+radius*math.sin(Rad) 
         return self.update_coord([x, y]) #Added/Edited 
    
        def UpdateCanvasSize(self, event): 
         """Permit to resize the canvas to the window""" 
         self.SizeX, self.SizeY = self.master.winfo_width(), self.master.winfo_height() 
         self.SystemCanvas.config(width=int(self.SizeX*0.75)-20, height=self.SizeY-20) 
    
        def move_start(self, event): 
         """Detect the beginning of the move""" 
         self.SystemCanvas.scan_mark(event.x, event.y) 
         self.SystemCanvas.focus_set() #security, set the focus on the Canvas 
    
        def move_move(self, event): 
         """Detect the move of the mouse""" 
         self.SystemCanvas.scan_dragto(event.x, event.y, gain=1) 
    
        def zoomer(self,event): 
         """Detect the zoom action by the mouse. Zoom on the mouse focus""" 
         true_x = self.SystemCanvas.canvasx(event.x) 
         true_y = self.SystemCanvas.canvasy(event.y) 
         if (event.delta > 0): 
          self.SystemCanvas.scale("all", true_x, true_y, 1.2, 1.2) 
          self.scale *= 1.2 #**Added 
         elif (event.delta < 0): 
          self.SystemCanvas.scale("all", true_x, true_y, 0.8, 0.8) 
          self.scale *= 0.8 #**Added 
         #self.SystemCanvas.configure(scrollregion = self.SystemCanvas.bbox("all")) #**Removed (This disables scrollbar after zoom) 
    
    if __name__ == '__main__': 
        root = tk.Tk() 
        root.geometry('1125x750') 
        app = Example(root) 
        root.mainloop() 
    
    관련 문제