2016-11-15 92 views
0

在這個測試腳本中,我畫了一個正方形,可以使用鼠標滾輪放大。 如果我右鍵單擊單元格內部,我會得到正確的單元格座標(不是x和y,而是列和行):這正是我期望它在後臺寫入控制檯的內容。 如果我通過按下鼠標左鍵並將其拖動到其他地方來移動畫布,則座標不再正確。畫布絕對和相對座標,delta像素檢索

我在哪裏可以得到delta x和delta y(或偏移量)以回饋正確的信息?

供參考: 1)get_pos()是執行檢查併產生結果的方法。 2)以下代碼已經在運行Python 3.5.2的Ubuntu 16.10(帶有最新更新)上進行了測試。

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 
    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 = 1 

    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 

    zoom = self.zoom 
    if self.drawn() and 1 != zoom: 
     if self.zoom < 1: 
      self.zoom = zoom = 1 
      print('no zooming below 1.') 
     else: 
      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:', self.zoom, ' col, row:', 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 = 9 

    self.zoom += 1 
    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 -= 1 
    if self.zoom < 1: 
     print("Can't go below one.") 
     self.zoom = 1 
     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) 

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

    scale = zoom * 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 'canvas' not 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() 

回答

0

看着previously answered question,我學會了如何找到增量X和增量Y我一直在尋找。

所以,解決的辦法是:

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) 

     # the following line stores deltax and deltay into x0, y0 
     x0, y0 = int(self.canvasx(0)), int(self.canvasy(0)) 

     # then it is trivial to compute the solution 
     xa, ya = x1 - x0, y1 - y0 
     xb, yb = x2 - x0, y2 - y0 

     if not (xa <= x <= xb and ya <= y <= yb): 
      print('Here we are out of bounds.') 
      return None, None 

     scale = zoom * cell_dim 

     col = (x - xa) // scale 
     row = (y - ya) // scale 

     return col, row