【问题标题】:Python code problem, application has been destroyed Tcl errorPython代码问题,应用程序已被破坏 Tcl错误
【发布时间】:2011-09-02 06:29:37
【问题描述】:

我正在制作一个 Tkinter GUI,除了调用图像之外什么都不做 - 当然,我一直在努力寻找像样的 tkinter 文档。

我的代码中有一行似乎无法按要求执行 - 我想调用字典中的所有值,并在调用下一个值之前为每个值单独打印和拉取相同名称的图像.我已经尝试过 dict.itervalues() 和 dict.values() 并且似乎无法完全弄清楚任何事情......

无论如何,这里是sn-p:

for key in ansDict.iterkeys(): #using the iterkeys function... kind of
    x=key

    root = tk.Tk() # root window created (is this in the right place?)
    root.title('C H E M I S T R Y   A B C\'s')

    frameAns=tk.Frame(root)
    frameAns.grid(row=0, column=0, sticky=tk.NW)

    for i in range(len(ansDict[x])):
        print '-->' + ansDict[x][i]

    for value in ansDict.itervalues(): #This is the most important part

        for i in range(len(value)): #pulls value list from dictionary named ansDict
            picRef1 = Image.open(value[i] + '.jpg') #calls image file by the same name using PIL
            photo1 = ImageTk.PhotoImage(picRef1, master=root)

            button1 = tk.Button(frameAns, compound=tk.TOP, image=photo1, text=str(value[i]) + '\nClose me!', bg='white') #pulls up button onto which the image is pasted
            button1.grid(sticky=tk.NW, padx=2, pady=2) #places button on grid
            button1.image=photo1

            root.mainloop()

最后,它拉出一两张图片,然后我收到以下错误:

TclError: 无法调用“图像”命令:应用程序已被销毁

我不知道出了什么问题。我无法移动图像命令,并且我需要以某种方式“保存”它,以免它被破坏。我知道这里还有其他代码错误,但我认为如果我发现了我得到的 TclError,我可以直接设置其他所有内容。

如果有更简单的方法来做这一切,请告诉!

【问题讨论】:

    标签: python windows tkinter pythonw


    【解决方案1】:

    这是一种可能性,尽管它的结构与您的示例不同。它将四个 100 像素的正方形图像堆叠在一起。我相信您需要为每个 Image 对象保留一个单独的引用,所以我将它们藏在 images 字典中。

    from Tkinter import *
    import os
    from PIL import Image, ImageTk
    
    image_names = { '1':'one','2':'two','3':'three','4':'four' }
    images = {}
    
    root = Tk()
    root.title("HELLO")
    frm = Frame(root)
    
    for v in image_names.itervalues():
       images[v] = {}
       images[v]['i']  = Image.open("%s%s.jpg" % (os.path.dirname(__file__), v))
       images[v]['pi'] = ImageTk.PhotoImage(images[v]['i'])
       images[v]['b']  = Button(frm, image=images[v]['pi'])
       images[v]['b'].pack()
    
    frm.pack()
    
    mainloop()
    

    这是一个讨论 PhotoImage 类的好链接。

    http://effbot.org/tkinterbook/photoimage.htm

    【讨论】:

      【解决方案2】:

      您似乎没有得到Event-driven programming 的概念。您应该创建一次整个 GUI,用小部件填充它,设置事件,然后进入无限循环。 GUI 应该根据您的事件到函数绑定调用回调函数。所以你的程序的那些部分绝对应该只被调用一次:root = tk.Tk()root.mainloop()

      编辑:添加了事件驱动编程“创意示例”。

      from Tkinter import *
      
      master = Tk()
      
      def callback():
          print "click!"
      
      b = Button(master, text="OK", command=callback)
      b.pack()
      
      mainloop()
      

      【讨论】:

      • 我不太明白。我需要将我的根窗口构造函数和主循环移到代码块之外并移到最外面的部分(如果我对程序部分的引用错误,我深表歉意)并且只调用它们一次。我明白了。我还需要使用回调函数对根窗口的内容进行更改,这是我真的不知道该怎么做的部分。
      • 你非常了解第一部分。请参阅 jtp 的答案以了解如何做到这一点,它提供了一个很好的例子。至于回调函数:几乎任何 GUI 的主要思想是,当您设置小部件(例如 Button)时,您可以将按下按钮时生成的事件绑定到某个函数。这种类型的函数称为callback。结果很简单,当你按下按钮时,函数被调用。我不使用 Tk,所以我不太确定,但我找到了一个很好的例子,所以我会将它添加到我的答案中。
      • 根据经验,当您的应用程序出现时,您应该停留在mainloop。此后您的应用程序所做的任何事情都应通过回调函数完成。
      【解决方案3】:

      我已经四处寻找一个好的解决方案,但还没有找到合适的解决方案。查看 Tkinter.py 类,它看起来像 Image del 值是:

      def __del__(self):
          if self.name:
              try:
                  self.tk.call('image', 'delete', self.name)
              except TclError:
                  # May happen if the root was destroyed
                  pass
      

      这意味着如果您想进行 BRUTAL hack,您可以按照 jtp 链接中的说明设置 PhotoImage。

      photo = tk.PhotoImage(file="C:/myimage.gif")
      widget["image"] = photo
      widget.image = photo
      

      然后您可以在程序退出之前执行以下 hack:

      photo.name = None
      

      这将阻止它在 PhotoImage 删除中尝试自行清理,并阻止在 del 方法中调用异常。我真的不建议你这样做,除非你的背靠在墙上,而且你别无选择。

      我会继续研究这个问题,如果我找到更好的解决方案,我会用更好的解决方案编辑这篇文章(希望在那之前有人会给出正确的解决方案)。

      【讨论】:

      • del 方法改成这样:
      • 我能够在 del 方法中捕捉到异常,但惊讶地看到抛出了什么。 (, TclError('can\'t invoke "image" command: application has been destroy',), ) 看起来这是一个被抛出的 TclError (还没有被 del 发现。这让我想知道 Tkinter 的作者做了什么才没有看到这个问题......将进一步调查。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多