Python Tkinter中未显示选择区域
我正在开发一个应用程序,允许用户根据自己的选择缩放图形的一部分。我能够得到初始的x,y坐标Python Tkinter中未显示选择区域,python,matplotlib,tkinter,Python,Matplotlib,Tkinter,我正在开发一个应用程序,允许用户根据自己的选择缩放图形的一部分。我能够得到初始的x,y坐标(x0,y0),以及最终的x,y坐标(x1,y1)。但是完全不知道为什么选择区域没有出现 from Tkinter import * matplotlib.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg root = Tk() graph = Figure(figsize=(5,4), dpi=100
(x0,y0)
,以及最终的x,y坐标(x1,y1)
。但是完全不知道为什么选择区域没有出现
from Tkinter import *
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
self.rect = ax.patch
self.rect.set_facecolor('green')
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
print 'press'
self.is_pressed = True
self.x0 = event.xdata
self.y0 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
def on_motion(self, event):
if self.is_pressed is True:
print 'panning'
self.x1 = event.xdata
self.y1 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print 'release'
self.is_pressed = False
self.x1 = event.xdata
self.y1 = event.ydata
print(self.x1, self.x0)
print(self.y1, self.y0)
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()
我从这个问题中得到了帮助
我得到的结果是
press
(0.0, 1.4007056451612905)
(0.0, 6.9296116504854366)
panning
(1.4007056451612905, 1.4007056451612905)
(6.8932038834951452, 6.9296116504854366)
panning
(None, 1.4007056451612905)
(None, 6.9296116504854366)
panning
(None, 1.4007056451612905)
(None, 6.9296116504854366)
release
(None, 1.4007056451612905)
(None, 6.9296116504854366)
您需要在事件更改时更新这些内容:
def on_motion(self, event):
if self.is_pressed is True:
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print 'release'
self.is_pressed = False
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
按原样,他们将在坐标(2.5,5)处连续绘制一个固定大小的矩形,宽度和高度为1
类似于你所看到的问题,类似于这样的工作
def on_press(self, event):
print('press')
self.is_pressed = True
self.x0 = event.xdata
self.y0 = event.ydata
def on_motion(self, event):
self.x1, self.y1 = event.xdata, event.ydata
if (self.is_pressed is True and
self.x1 is not None and
self.y1 is not None):
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print('release')
self.is_pressed = False
self.x1, self.y1 = event.xdata, event.ydata
try:
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
except TypeError:
if (self.x1 is None or self.y1 is None):
return
else:
raise
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
请注意,矩形标注取自事件。我添加了防护装置,以防止事件无法正确解释坐标时发生意外
@furas在评论中提出了一个很好的观点,将坐标初始化为浮动是个好主意
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
您需要在事件更改时更新这些内容:
def on_motion(self, event):
if self.is_pressed is True:
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print 'release'
self.is_pressed = False
self.x1 = event.xdata
self.y1 = event.ydata
self.rect.set_width(1)
self.rect.set_height(1)
self.rect.set_xy((2.5, 5))
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
按原样,他们将在坐标(2.5,5)处连续绘制一个固定大小的矩形,宽度和高度为1
类似于你所看到的问题,类似于这样的工作
def on_press(self, event):
print('press')
self.is_pressed = True
self.x0 = event.xdata
self.y0 = event.ydata
def on_motion(self, event):
self.x1, self.y1 = event.xdata, event.ydata
if (self.is_pressed is True and
self.x1 is not None and
self.y1 is not None):
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.rect.set_linestyle('dashed')
self.ax.figure.canvas.draw()
def on_release(self, event):
print('release')
self.is_pressed = False
self.x1, self.y1 = event.xdata, event.ydata
try:
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
except TypeError:
if (self.x1 is None or self.y1 is None):
return
else:
raise
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
请注意,矩形标注取自事件。我添加了防护装置,以防止事件无法正确解释坐标时发生意外
@furas在评论中提出了一个很好的观点,将坐标初始化为浮动是个好主意
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
这对我很有用:
from Tkinter import *
from matplotlib.figure import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
# should be Rectangle((0,0),0,0)
self.rect = Rectangle((10,10),100,100)
self.ax.add_patch(self.rect)
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
self.is_pressed = True
if event.xdata is not None and event.ydata is not None:
self.x0, self.y0 = event.xdata, event.ydata
print 'press:', self.x0, self.y0
# only remove old rectangle
self.rect.set_width(0)
self.rect.set_height(0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
# color and linestyle for future motion
self.rect.set_facecolor('red')
self.rect.set_linestyle('dashed')
def on_motion(self, event):
if self.is_pressed:
if event.xdata is not None and event.ydata is not None:
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
print 'rect:', self.x0, self.y0, self.x1, self.y1, (self.x1-self.x0), (self.y1-self.y0)
def on_release(self, event):
self.is_pressed = False
print 'release:', event.xdata, event.ydata
# change only color and linestyle
#self.rect.set_width(self.x1 - self.x0)
#self.rect.set_height(self.y1 - self.y0)
#self.rect.set_xy((self.x0, self.y0))
self.rect.set_facecolor('blue')
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()
这对我很有用:
from Tkinter import *
from matplotlib.figure import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
# should be Rectangle((0,0),0,0)
self.rect = Rectangle((10,10),100,100)
self.ax.add_patch(self.rect)
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
self.is_pressed = True
if event.xdata is not None and event.ydata is not None:
self.x0, self.y0 = event.xdata, event.ydata
print 'press:', self.x0, self.y0
# only remove old rectangle
self.rect.set_width(0)
self.rect.set_height(0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
# color and linestyle for future motion
self.rect.set_facecolor('red')
self.rect.set_linestyle('dashed')
def on_motion(self, event):
if self.is_pressed:
if event.xdata is not None and event.ydata is not None:
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
print 'rect:', self.x0, self.y0, self.x1, self.y1, (self.x1-self.x0), (self.y1-self.y0)
def on_release(self, event):
self.is_pressed = False
print 'release:', event.xdata, event.ydata
# change only color and linestyle
#self.rect.set_width(self.x1 - self.x0)
#self.rect.set_height(self.y1 - self.y0)
#self.rect.set_xy((self.x0, self.y0))
self.rect.set_facecolor('blue')
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()
谢谢你的回复。但是我按照你说的方式做了&它生成了一个错误
self.rect.set\u width(self.x1-self.x0)TypeError:不支持的操作数类型-:“NoneType”和“float”
哪个值是None
?您是否确实在按下功能时设置了self.y0
和self.x0
?你在画布内部点击了吗?@Mahasish Shome你在\uuu init\uuuu
中设置了self.x1=None
(还有其他)使用self.x1=0
@furas:我已经尝试了0
,现在我在Tkinter回调回溯(最近一次调用最后一次):文件“C:/Users/VAIO/test.pyw”中得到了类似的释放异常,第52行,on_release self.rect.set_width(self.x1-self.x0)TypeError:不支持的操作数类型-:“NoneType”和“float”
但是event.x,event.y
在on_motion
中给出正确的值。感谢您的回复。但是我按照你说的方式做了&它生成了一个错误self.rect.set\u width(self.x1-self.x0)TypeError:不支持的操作数类型-:“NoneType”和“float”
哪个值是None
?您是否确实在按下功能时设置了self.y0
和self.x0
?你在画布内部点击了吗?@Mahasish Shome你在\uuu init\uuuu
中设置了self.x1=None
(还有其他)使用self.x1=0
@furas:我已经尝试了0
,现在我在Tkinter回调回溯(最近一次调用最后一次):文件“C:/Users/VAIO/test.pyw”中得到了类似的释放异常,第52行,on_release self.rect.set_width(self.x1-self.x0)TypeError:不支持的操作数类型-:“NoneType”和“float”
但event.x,event.y
在中对运动给出正确的值
。平移时是否离开画布?@MrAlias否我只是移动一点,鼠标光标从原始位置的像素运动生成无
。平移时是否离开画布?@MrAlias否我只是从原始位置移动一点鼠标光标的像素运动生成无
。真是令人印象深刻的研究!!!您能告诉我为什么没有矩形
,它就不能工作吗?为什么您在发布时注释掉了属性,例如设置宽度、设置高度、设置xy
+1谢谢你的努力。也许它需要新的对象矩形
来显示它。也许以前它不是矩形,而是背景或其他东西。我不需要在发布时的中设置宽度、设置高度、设置xy
,因为运动时的可以完成所有工作-它总是获得最新的坐标。除此之外,我可以在鼠标位于图形外部(在页边空白处)时释放按钮,然后我就不需要这个坐标-尤其是那个扩展数据,ydata将是无的。真是令人印象深刻的研究!!!您能告诉我为什么没有矩形
,它就不能工作吗?为什么您在发布时注释掉了属性,例如设置宽度、设置高度、设置xy
+1谢谢你的努力。也许它需要新的对象矩形
来显示它。也许以前它不是矩形,而是背景或其他东西。我不需要在发布时的中设置宽度、设置高度、设置xy
,因为运动时的可以完成所有工作-它总是获得最新的坐标。除此之外,当鼠标位于图形外部(在边距上)时,我可以释放按钮,然后我就不需要这个坐标——特别是扩展数据,ydata将是无的。