动态在Tkinter画布上绘图的问题
一个问题: 如何在点击按钮时动态地在Tkinter的Canvas对象上绘图?
这个话题最初是由用户339860提出的(见1),分成了两个部分,但第二部分的问题还没有得到解决。我也遇到了同样的问题,具体来说我无法通过按钮事件在Canvas对象上绘图。解决这个问题对我和用户339860都有帮助,请大家看看。
这个应用程序创建了两个框架,分别放在左边和右边,第二个框架里包含了Canvas对象。我在第一个框架里有一个按钮,这个按钮绑定了一个名为drawRectangle的函数。应用程序运行得很好,它甚至能通过create_rectangle方法在Canvas对象上绘制一个矩形,直到你点击按钮。当你点击按钮时,会出现以下消息:
tkinter_app_27Nov2010.py", 第25行,在drawRectangle中 self.myCan.create_rectangle(64,64,110,110,fill='blue') AttributeError: 'NoneType'对象没有'create_rectangle'属性
我想这可能和Canvas对象的作用域有关,所以我创建了一个类级别的变量并设置为None,但这并没有解决问题。我考虑过Canvas的显示列表(见2),但Tk的手册里没有找到我能找到的添加新对象的方法。
代码:
# tkinter_app_27Nov2010.py
from Tkinter import *
class Application(Frame):
myCan = None
def createWidgets(self):
uiFrame = Frame(self,width=300,height=30)
uiFrame.configure(background='#e0e0e0')
uiFrame.grid(row=0,column=0,sticky=N+S)
outputFrame = Frame(self,width=300,height=300,background='#C0C0C0')
outputFrame.grid(row=0,column=1)
newBtn = Button(uiFrame,text="testing",command=self.drawRectangle)
newBtn.grid(row=0,column=0)
fillLbl = Label(uiFrame,text='-').grid(row=1,sticky=N+S)
newLBL = Label(outputFrame,text="another testing",background='#C0C0C0')
newLBL.grid(row=0)
myCan = Canvas(outputFrame,width=300,height=300,borderwidth=1,relief='sunken')
myCan.grid(row=1)
myCan.create_rectangle(34,34,50,50,fill='red')
def drawRectangle(self):
self.myCan.create_rectangle(64,64,110,110,fill='blue')
def __init__(self,master):
Frame.__init__(self,master)
self.pack()
self.createWidgets()
root = Tk() myApp = Application(master=root) root.title("Tkinter 测试!") myApp.mainloop()
一定有办法获取Tkinter Canvas对象用来更新自己的“损坏/修复显示模型”(见3)。请帮帮我!
参考资料:
stackoverflow.com/questions/2824041/dynamically-add-items-to-tkinter-canvas
effbot.org/tkinterbook/canvas.htm#performance-issues
2 个回答
这里没有叫“self.myCan”的对象。在你使用它之前,得先把它创建成一个画布对象或者其他什么东西。根据你做的事情,你可能还需要调用一下update_idletasks()。
这是一个关于Python的问题,不是关于tkinter
的。你在createWidgets
里面定义了局部变量,但没有把它们设置为实例属性。你需要用self.foo
来做到这一点:
>>> class Foo:
... def __init__(self):
... bar = "baz"
...
>>> class Bar:
... def __init__(self):
... self.bar = "baz"
...
>>> foo = Foo()
>>> foo.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Foo instance has no attribute 'bar'
>>> bar = Bar()
>>> bar.bar
'baz'
注意,你说得没错:问题确实和Canvas
的作用域有关。更准确地说,是和myCan
这个变量的作用域有关。如果你没有定义类变量myCan
,那么查找self.myCan
时就会出现一个很明显的AttributeError
错误。