【问题标题】:Problem Dynamically Drawing to Tkinter Canvas Object问题动态绘制到 Tkinter 画布对象
【发布时间】:2011-05-16 15:37:54
【问题描述】:

一个问题:如何通过单击按钮动态绘制到 Tkinter Canvas 对象?

此主题最初由 user339860(参见 1)作为一个两部分问题发布,但该问题的第二部分尚未解决。我遇到了同样的问题,特别是我无法从按钮事件中绘制到 Canvas 对象。回答这个问题将帮助两个人,我自己和 user339860;请看一下。

应用程序创建左右两个框架,第二个框架包含 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 对象的范围有关,所以我创建了一个 class level 变量设置为 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 = 应用程序(主 = 根) root.title("Tkinter 测试!") myApp.mainloop()


必须有一种方法来处理 Tkinter Canvas 对象用于更新自身的“损坏/修复显示模型”(参见 3)。请帮忙!

参考资料:

  1. stackoverflow.com/questions/2824041/dynamically-add-items-to-tkinter-canvas

  2. www.tcl.tk/man/tcl8.4/TkCmd/canvas.htm#M16

  3. effbot.org/tkinterbook/canvas.htm#performance-issues

【问题讨论】:

  • 您引用为 (1) 的问题的第二部分已回答。该问题的两个部分都是由同一行代码引起的。在这种情况下,问题与您遇到的问题不同。

标签: python tkinter-canvas


【解决方案1】:

这是一个 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

【讨论】:

  • 谢谢你,katrielalex!您的洞察力以及 Wooee 完美地解决了这个问题!我非常感谢您提供的示例,以便我可以更清楚地看到实例属性的正确应用。杰出的!再次感谢。
  • @code:没问题!一般的经验法则是 Python 喜欢局部变量,并且一切都将在其范围内是本地的,除非它有某些理由不这样做(globalnonlocal,...)。
【解决方案2】:

没有对象“self.myCan”。您必须先将其创建为画布对象或其他任何东西,然后才能使用它。您可能还需要调用 update_idletasks(),具体取决于您的操作。

【讨论】:

  • 谢谢你,哇!你和 katrielalex 都是对的!正确使用 self (self.myCan) 是解决问题所需要的。感谢您抽出宝贵时间审查并发表您对此的见解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 2018-03-28
  • 2017-01-10
  • 2020-10-14
  • 2018-11-05
相关资源
最近更新 更多