未创建 Canvas 的图像

Image for Canvas is not created

所以我想要一个 window 可以在点击后更新显示的图片。 只要没有进一步的 tk.Tk() 实例(remove/add 下面代码的第 8 行),它就可以正常工作。

如果之前创建过,则会引发此错误:

line 29, in CreatePeakSelectionWindow
[...]
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.img1)
[...]
_tkinter.TclError: image "pyimage1" doesn't exist

我想我需要向 Tk() 传递一些参数? 我什至不知道去哪里解决这个问题并了解它是如何引起的。 遗憾的是,这个小部件将用于允许手动选择一些峰,并且应该在外部 window 中完成。 仅供参考,为了简单起见,所有数组都是虚拟数组(随机数组)。

非常感谢您的帮助!

导致问题的代码如下:

import tkinter as tk
import numpy as np
from PIL import Image,ImageTk
import matplotlib.pyplot as plt

class Dummy:
    def __init__(self):
        self.MainWin = tk.Tk() #>this line causes the issue
        imgs = np.random.randint(0,255,(512,624,2))
        self.img = imgs[:,:,0] #self.img is a numpy array in black and white
        self.imgSize = self.img.shape
        self.peakList = np.array([[200,200],[300,400]])
        self.selectedIndexOfPeaksList = []
        self.peakListGenerated = True

    def CreatePeakSelectionWindow(self):
        if self.peakListGenerated:
            self.selectedIndexOfPeaksList = []
            self.PeakSelectionWindow = tk.Tk()
            self.PeakSelectionWindow.protocol("WM_DELETE_WINDOW",self.PeakSelectionWindowClose)
            self.PeakSelectionWindow.geometry("%sx%s"%(self.imgSize[1],self.imgSize[0]))
            self.PeakSelectionWindow.title("Peak Slection")
            self.img1 = ImageTk.PhotoImage(image=Image.fromarray(self.img))
            self.imgCanvas = tk.Canvas(self.PeakSelectionWindow,width=self.imgSize[1],height=self.imgSize[0])
            self.imgCanvas.place(x=0,y=0)
            self.PeakSelectionWindow.bind("<Button 1>",self.LeftClick)
            self.PeakSelectionWindow.bind("<Button 3>",self.RightClick)
            self.PeakSelectionWindow.update()
            self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.img1)
        else:
            print("List of peaks has not yet been generated!",file=sys.stderr)

    def PeakSelectionWindowClose (self):
        if len(self.selectedIndexOfPeaksList) > 0:
            print("put extraction here")
            #self.selectedPeaksEntry.insert(tk.END,", ".join(map(str,self.selectedIndexOfPeaksList)))
        self.PeakSelectionWindow.destroy()

    def LeftClick(self,event):
        distance = np.sqrt((self.peakList[:,1]-event.x)**2+(self.peakList[:,0]-event.y)**2)
        index = np.argmin(distance)
        if index not in self.selectedIndexOfPeaksList:
            self.peakList[index]
            self.selectedIndexOfPeaksList += [index]
            newImg = np.random.randint(0,255,(self.img.shape[0],self.img.shape[1],3))
            self.PeakSelectionWindow.newImg = img = ImageTk.PhotoImage(image=Image.fromarray(newImg.astype("uint8"),mode="RGB"))
            self.imgCanvas.delete("all")
            self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
            self.imgCanvas.update()

    def RightClick (self,event):
        distance = np.sqrt((self.peakList[:,1]-event.x)**2+(self.peakList[:,0]-event.y)**2)
        index = np.argmin(distance)
        print(self.selectedIndexOfPeaksList)
        if index in self.selectedIndexOfPeaksList:
            if len(self.selectedIndexOfPeaksList) > 1:
                self.selectedIndexOfPeaksList.remove(index)
                newImg = np.random.randint(0,255,(self.img.shape[0],self.img.shape[1],3))
                self.PeakSelectionWindow.newImg = img = ImageTk.PhotoImage(image=Image.fromarray(newImg.astype("uint8"),mode="RGB"))
                self.imgCanvas.delete("all")
                self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
                self.imgCanvas.update()
            else:
                self.selectedIndexOfPeaksList = []
                self.PeakSelectionWindow.newImg = newImg = ImageTk.PhotoImage(image=Image.fromarray(self.img.astype("uint8")))
                self.imgCanvas.delete("all")
                self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
                self.imgCanvas.update()




if __name__ == "__main__":
    window = Dummy()
    window.CreatePeakSelectionWindow()
    tk.mainloop()

好的,所以我找到了解决方案。 额外的 window 需要是 class 和 tk.Toplevel()。 上述代码的所有更改为:

  • class Dummy:class Dummy (tk.Toplevel()):

  • def __init__(self):def __init__ (self,master):

  • self.peakSelectionWindowself(参考 master 传递给 class)

  • 任何 tk 对象(如按钮)也需要此 master 设置为 window 才能呈现

当然,第一个 window 的创建应该在 class 之外处理,将 windowName = tk.Tk() 传递给 Dummy 的调用,就像正常的 variable/reference.

如果您需要将 master 的变量共享给这个虚拟 class,我认为 windowName.variableName = 5 也使它们 known/accessable 在虚拟中(通过 self.variableName)。然而,这可能会很混乱,所以如果可能的话,请改为正常传递它们。