2016-12-15 2 views
0

Я не знаю, является ли мой вопрос глупым или сложным.Холст Tkinter: Масштаб на движущемся объекте

Итак, используя Tkinter и Canvas, мне удалось реализовать функцию прокрутки/масштабирования, которая отлично работает, благодаря этому сообщению Move and zoom a tkinter canvas with mouse. Я также добавляю привязку для изменения размера холста при изменении размера окна без проблем.

Использование coords и after, у меня нет проблем с перемещением object вокруг.

Неполадка пришла, когда я попытался объединить все.

  • Перемещение и не прокрутки: никаких проблем
  • скроллинг и масштабирование: ок
  • Zooming, перемещение и прокрутки: не работают

код ниже воспроизвести проблемы (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, который масштабирует заданную координату на основе масштабного коэффициента. Наконец, я позвонил в MoveObject и UpdatePosition.

Вот рабочий код;

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() 
Смежные вопросы