未创建 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.peakSelectionWindow
到 self
(参考 master
传递给 class)
任何 tk
对象(如按钮)也需要此 master
设置为 window 才能呈现
当然,第一个 window 的创建应该在 class 之外处理,将 windowName = tk.Tk()
传递给 Dummy
的调用,就像正常的 variable/reference.
如果您需要将 master 的变量共享给这个虚拟 class,我认为 windowName.variableName = 5
也使它们 known/accessable 在虚拟中(通过 self.variableName
)。然而,这可能会很混乱,所以如果可能的话,请改为正常传递它们。
所以我想要一个 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.peakSelectionWindow
到self
(参考master
传递给 class)任何
tk
对象(如按钮)也需要此master
设置为 window 才能呈现
当然,第一个 window 的创建应该在 class 之外处理,将 windowName = tk.Tk()
传递给 Dummy
的调用,就像正常的 variable/reference.
如果您需要将 master 的变量共享给这个虚拟 class,我认为 windowName.variableName = 5
也使它们 known/accessable 在虚拟中(通过 self.variableName
)。然而,这可能会很混乱,所以如果可能的话,请改为正常传递它们。