2016-11-14 1 views
0

캔버스에 직사각형을 그릴 때 나는 절대 좌표 (canvasx(), canvasy())와 상대 좌표 (나는 통과 한 좌표)를 알고 있습니다. 그런 다음 캔버스 scan_mark() 및 scan_dragto() 메소드를 사용하여 캔버스를 이동할 수 있습니다. 사용자가 위치를 잃어 버렸을 수도있는 사각형을 다시 센터링하려면 이러한 scan_mark()/scan_dragto() 호출 중 하나 이상이 수행되기 전에 원래 위치로 어떻게 되돌릴 수 있습니까? 재설정보기 명령/방법이 있습니까? 발생한 변화를 어떻게 추적 할 수 있습니까?tkinter에서 캔버스의 뷰를 어떻게 재설정 할 수 있습니까?

+0

가 처음 생성되면 캔버스의 그것의 좌표를 알고 있다면, 당신은 할 수 없었다 이러한 좌표를 저장하고 다시 설정하려는 경우 해당 값을 캔버스보기로 복원 할 수 있습니까? – davedwards

+0

나는 내가 만든 객체의 좌표를 알고 있지만 원래의 뷰로 돌아가려면 전체 캔버스를 가로 및/또는 세로로 스크롤해야하는 양을 모릅니다. 이것이 제가 가진 문제입니다. 이 델타는 어디에 저장/사용 가능합니까? –

답변

2

필자가 보았던 Tkinter 문서는이 점을 언급하지 않았지만 현재 Tk Canvas xview/yview 메서드는 매개 변수없이 호출하여 현재 스크롤 위치를 가져올 수 있습니다 (실제로는 두 요소의 튜플, 두 번째는 너에게 어떤 용도로도 사용되지 않는다). 그래서, 다음은 (테스트하지) 작동합니다 :

저장 위치 :

origX = yourcanvas.xview()[0] 
origY = yourcanvas.yview()[0] 

위치 복원 : 이전 코멘트 @jasonharper에서와 같이

yourcanvas.xview_moveto(origX) 
yourcanvas.yview_moveto(origY) 
+0

감사합니다. jasonharper. 이것은 내가 찾고 있었던 바로 그 것이다. 그것은 효과가 있었다. –

0

을, 그의 제안했다. 동일한 문제가있는 다른 사람들을 위해 작업 예제를 첨부하여 자랑스럽게 잘 정리하지는 못했지만 확대/축소 및보기 드래그 및 재설정이 작동하는 방식을 볼 수있는 방법을 제공 할 수 있습니다.

import tkinter as tk 
import tkinter.ttk as ttk 


class GriddedMazeCanvas(tk.Canvas): 

    def almost_centered(self, cols, rows): 

     width = int(self['width']) 
     height = int(self['height']) 
     cell_dim = self.settings['cell_dim'] 
     rows = rows % height 
     cols = cols % width 

     w = cols * cell_dim 
     h = rows * cell_dim 

     if self.zoom < 0: 
      raise ValueError('zoom is negative:', self.zoom) 

     zoom = self.zoom // 2 + 1 
     if self.drawn() and 1 != zoom: 
      w *= zoom 
      h *= zoom 

     h_shift = (width - w) // 2 
     v_shift = (height - h) // 2 

     return [h_shift, v_shift, 
       h_shift + w, v_shift + h] 

    def __init__(self, *args, **kwargs): 
     if 'settings' not in kwargs: 
      raise ValueError("'settings' not passed.") 
     settings = kwargs['settings'] 
     del kwargs['settings'] 

     super().__init__(*args, **kwargs) 

     self.config(highlightthickness=0) 

     self.settings = settings 
     self.bind_events() 

    def draw_maze(self, cols, rows): 

     self.cols = cols 
     self.rows = rows 

     if self.not_drawn(): 
      self.cells = {} 
      self.cell_dim = self.settings['cell_dim'] 
      self.border_thickness = self.settings['border_thickness'] 
      self.zoom = 0 

     self.delete(tk.ALL) 

     maze, coords = self._draw_maze(cols, rows, fix=False) 
     lines = self._draw_grid(coords) 

     return maze, lines 

    def _draw_maze(self, cols, rows, fix=True): 
     data = self.settings 

     to_max = data['to_max'] 
     border_thickness = data['border_thickness'] 
     poligon_color = data['poligon_color'] 
     poligon_border_color = data['poligon_border_color'] 

     coords = self.almost_centered(cols, rows) 

     if fix: 
      # Fix for the disappearing NW borders 
      if to_max == cols: 
       coords[0] += 1 
      if to_max == rows: 
       coords[1] += 1 

     maze = self.create_rectangle(*coords, 
            fill=poligon_color, 
            outline=poligon_border_color, 
            width=border_thickness, 
            tag='maze') 
     return maze, coords 

    def _draw_grid(self, coords): 
     data = self.settings 
     poligon_border_color = data['poligon_border_color'] 
     cell_dim = data['cell_dim'] 

     if coords is None: 
      if self.not_drawn(): 
       raise ValueError('The maze is still uninitialized.') 
      x1, y1, x2, y2 = self.almost_centered(self.cols, self.rows) 
     else: 
      x1, y1, x2, y2 = coords 

     if self.drawn() and 0 != self.zoom: 
      if self.zoom < 0: 
       self.zoom = 0 
       print('no zooming at negative values.') 
      else: 
       zoom = self.zoom // 2 + 1 
       cell_dim *= zoom 

     lines = [] 

     for i, x in enumerate(range(x1, x2, cell_dim)): 
      line = self.create_line(x, y1, x, y2, 
            fill=poligon_border_color, 
            tags=('grid', 'grid_hl_{}'.format(i))) 
      lines.append(line) 

     for i, y in enumerate(range(y1, y2, cell_dim)): 
      line = self.create_line(x1, y, x2, y, 
            fill=poligon_border_color, 
            tags=('grid', 'grid_vl_{}'.format(i))) 
      lines.append(line) 

     return lines 

    def drawn(self): 
     return hasattr(self, 'cells') 

    def not_drawn(self): 
     return not self.drawn() 

    def bind_events(self): 

     self.bind('<Button-4>', self.onZoomIn) 
     self.bind('<Button-5>', self.onZoomOut) 

     self.bind('<ButtonPress-1>', self.onScrollStart) 
     self.bind('<B1-Motion>', self.onScrollMove) 
     self.tag_bind('maze', '<ButtonPress-3>', self.onMouseRight) 

    def onScrollStart(self, event): 
     print(event.x, event.y, self.canvasx(event.x), self.canvasy(event.y)) 
     self.scan_mark(event.x, event.y) 

    def onMouseRight(self, event): 
     col, row = self.get_pos(event) 
     print('zoom, col, row:', self.zoom, col, row) 

    def onScrollMove(self, event): 
     delta = event.x, event.y 
     self.scan_dragto(*delta, gain=1) 

    def onZoomIn(self, event): 
     if self.not_drawn(): 
      return 

     max_zoom = 16 

     self.zoom += 2 
     if self.zoom > max_zoom: 
      print("Can't go beyond", max_zoom) 
      self.zoom = max_zoom 
      return 

     print('Zooming in.', event.num, event.x, event.y, self.zoom) 
     self.draw_maze(self.cols, self.rows) 

    def onZoomOut(self, event): 
     if self.not_drawn(): 
      return 

     self.zoom -= 2 
     if self.zoom < 0: 
      print("Can't go below zero.") 
      self.zoom = 0 
      return 

     print('Zooming out.', event.num, event.x, event.y, self.zoom) 
     self.draw_maze(self.cols, self.rows) 

    def get_pos(self, event): 
     x, y = event.x, event.y 
     cols, rows = self.cols, self.rows 
     cell_dim, zoom = self.cell_dim, self.zoom 
     x1, y1, x2, y2 = self.almost_centered(cols, rows) 

     if not (x1 <= x <= x2 and y1 <= y <= y2): 
      print('Here we are out of bounds.') 
      return None, None 

     scale = (zoom // 2 + 1) * cell_dim 

     col = (x - x1) // scale 
     row = (y - y1) // scale 

     return col, row 


class CanvasButton(ttk.Button): 

    def freeze_origin(self): 
     if not hasattr(self, 'origin'): 
      canvas = self.canvas 
      self.origin = canvas.xview()[0], canvas.yview()[0] 

    def reset(self): 
     canvas = self.canvas 
     x, y = self.origin 
     canvas.yview_moveto(x) 
     canvas.xview_moveto(y) 

    def __init__(self, *args, **kwargs): 
     if not 'canvas' in kwargs: 
      raise ValueError("'canvas' not passed.") 
     canvas = kwargs['canvas'] 
     del kwargs['canvas'] 

     super().__init__(*args, **kwargs) 
     self.config(command=self.reset) 

     self.canvas = canvas 


root = tk.Tk() 

settings = {'cell_dim': 3, 
      'to_max': 200, 
      'border_thickness': 1, 
      'poligon_color': '#F7F37E', 
      'poligon_border_color': '#AC5D33'} 

frame = ttk.Frame(root) 
canvas = GriddedMazeCanvas(frame, 
          settings=settings, 
          width=640, 
          height=480) 
button = CanvasButton(frame, text='Reset', canvas=canvas) 
button.freeze_origin() 

canvas.draw_maze(20, 10) 

canvas.grid(row=0, column=0, sticky=tk.NSEW) 
button.grid(row=1, column=0, sticky=tk.EW) 
frame.rowconfigure(0, weight=1) 
frame.grid() 

root.mainloop() 

파이썬 3.4로 테스트 최신 우분투 16.10 (이벤트 : MouseLeft, Mouseright,을 MouseWheel, ButtonPress) HTH

관련 문제