Python 画布绝对和相对坐标,增量像素检索
在这个测试脚本中,我画了一个正方形,可以用鼠标滚轮放大。 如果我在单元格内单击鼠标右键,我会得到正确的单元格坐标(不是x和y,而是列和行):这正是我希望它在后台写入控制台的内容。 相反,如果我通过按下鼠标左键并将其拖动到其他位置来移动画布,则坐标不再正确 我从哪里获得delta x和delta y(或偏移量)以返回正确的信息 供参考: 1) get_pos()是执行检查并生成结果的方法。 2) 以下代码已经在运行Python3.5.2的Ubuntu16.10(最新更新)上进行了测试Python 画布绝对和相对坐标,增量像素检索,python,python-3.x,tkinter,tkinter-canvas,Python,Python 3.x,Tkinter,Tkinter Canvas,在这个测试脚本中,我画了一个正方形,可以用鼠标滚轮放大。 如果我在单元格内单击鼠标右键,我会得到正确的单元格坐标(不是x和y,而是列和行):这正是我希望它在后台写入控制台的内容。 相反,如果我通过按下鼠标左键并将其拖动到其他位置来移动画布,则坐标不再正确 我从哪里获得delta x和delta y(或偏移量)以返回正确的信息 供参考: 1) get_pos()是执行检查并生成结果的方法。 2) 以下代码已经在运行Python3.5.2的Ubuntu16.10(最新更新)上进行了测试 import
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()
将tkinter作为tk导入
将tkinter.ttk导入为ttk
类GriddedMazeCanvas(tk.Canvas):
def几乎居中(自、列、行):
宽度=int(自身['width'])
高度=整数(自['height'])
cell\u dim=自身设置['cell\u dim']
行数=行数%高度
cols=cols%宽度
w=cols*单元尺寸
h=行*单元尺寸
如果self.zoom<0:
raise VALUERROR('缩放为负:',self.zoom)
zoom=self.zoom
如果self.draw()和1!=缩放:
w*=缩放
h*=缩放
h_shift=(宽度-w)//2
v_shift=(高度-h)//2
返回[h_移位,v_移位,
h_shift+w,v_shift+h]
定义初始化(self,*args,**kwargs):
如果“设置”不在kwargs中:
raise VALUERROR(“'settings'未通过。”)
设置=kwargs['settings']
del kwargs[“设置”]
super()
self.config(highlightthickness=0)
self.settings=设置
self.bind_事件()
def draw_迷宫(自身、列、行):
self.cols=cols
self.rows=行
如果self.not_draw():
self.cells={}
self.cell\u dim=self.settings['cell\u dim']
self.border\u thickness=self.settings['border\u thickness']
self.zoom=1
self.delete(tk.ALL)
迷宫,坐标=self.\u绘图\u迷宫(cols,rows,fix=False)
直线=自绘制网格(坐标)
返回迷宫、线路
定义绘制迷宫(self、cols、rows、fix=True):
数据=自我设置
to_max=数据['to_max']
边框厚度=数据[“边框厚度”]
poligon_color=数据['poligon_color']
poligon\u border\u color=数据['poligon\u border\u color']
coords=self.几乎居中(列、行)
如果修复:
#修正消失的西北边界
如果to_max==cols:
坐标[0]+=1
如果to_max==行:
坐标[1]+=1
迷宫=自我。创建矩形(*坐标,
填充=poligon\u颜色,
轮廓=poligon\u边框\u颜色,
宽度=边框厚度,
tag='maze')
返回迷宫,coords
定义绘制网格(自、坐标):
数据=自我设置
poligon\u border\u color=数据['poligon\u border\u color']
单元尺寸=数据['cell尺寸']
如果coords为无:
如果self.not_draw():
raise VALUERROR('迷宫仍未初始化')
x1,y1,x2,y2=自几乎居中(self.cols,self.rows)
其他:
x1,y1,x2,y2=坐标
zoom=self.zoom
如果self.draw()和1!=缩放:
如果self.zoom<1:
self.zoom=zoom=1
打印('不在1以下缩放')
其他:
单元尺寸*=缩放
行=[]
对于枚举中的i,x(范围(x1,x2,单元格尺寸)):
线=自身。创建线(x,y1,x,y2,
填充=poligon\u边框\u颜色,
标签=('grid','grid_hl{}'。格式(i)))
行。追加(行)
对于枚举中的i,y(范围(y1,y2,单元格_-dim)):
线=自身。创建线(x1,y,x2,y,
填充=poligon\u边框\u颜色,
标签=('grid','grid_vl_{}'。格式(i)))
行。追加(行)
回程线
def绘制(自):
return hasattr(self,“cells”)
未绘制def(自):
返回非自绘制()
def绑定_事件(自):
self.bind(“”,self.onZoomIn)
self.bind(“”,self.onZoomOut)
self.bind(“”,self.onScrollStart)
self.bind(“”,self.onScrollMove)
self.tag_bind('maze','',self.onMouseRight)
def onScrollStart(自身、事件):
打印(event.x、event.y、self.canvasx(event.x)、self.canvasy(event.y))
自我扫描标记(事件x、事件y)
def onMouseRight(自身、事件):
列,行=自身获取位置(事件)
打印('zoom:',self.zoom,'col,row:',col,row)
def onScrollMove(自身、事件):
增量=事件x,事件y
自扫描绘图(*增量,增益=1)
def onZoomIn(自身,事件):
如果self.not_draw():
回来
最大缩放=9
self.zoom+=1
如果self.zoom>最大缩放:
打印(“无法超出”,最大缩放)
self.zoom=最大缩放
回来
打印('放大'、event.num、event.x、event.y、self.zoom)
self.draw_迷宫(self.cols、self.rows)
def onZoomOut(自身、事件):
如果self.not_draw():
回来
self.zoom-=1
如果self.zoom<1:
打印(“不能低于1”)
self.zoom=1
回来
打印('缩小'、event.num、event.x、event.y、self.zoom)
self.draw_迷宫(self.cols、self.rows)
def get_位置(自身、事件):
x、 y=事件.x,事件.y
cols,rows=self.cols,self.rows
单元格尺寸,缩放=self.cell尺寸,self.zoom
x1,y1,x2,y2=自几乎居中(列,行)
打印('x1,y1,x2,y2:',x1,y1,x2,y2,
'bbox:',self.bbox('maze'))
如果不是(x1看a,我学会了如何找到我要找的δ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
def get_pos(自身,事件):
x、 y=事件.x,事件.y
cols,rows=self.cols,self.rows
单元格尺寸,缩放=self.cell尺寸,self.zoom
x1,y1,x2,y2=自几乎居中(列,行)
#下一行将deltax和deltay存储到x0、y0中
x0,y0=int(self.canvasx(0)),int(self.canvasy(0))
#那就是琐事了