Tkinter 无法绘制到另一个 window
Tkinter cannot draw to another window
我想做一些应该相当简单的事情,但我正在努力让它发挥作用。
基本上我有 2 个 Tkinter windows(canvas_tk
和 control_tk
)。
在 canvas_tk
中,我想显示一张图片并在其上画一个圆圈。
在control_tk
中,我有一个输入要绘制的圆的半径的条目。
在我的代码中,关键行位于代码的最底部:
self.panel = tk.Label(canvas_tk, image=image)
如果我在 control_tk 中制作标签或者如果我不指定父级,它实际上可以正常工作并在 control_tk window 中绘制圆圈
但是我希望在 canvas_tk window
中绘制圆圈
self.panel = tk.Label(image=image) # Works
self.panel = tk.Label(control_tk, image=image) # Works
self.panel = tk.Label(canvas_tk, image=image) # Fails
这是我的最小代码:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
canvas_tk = tk.Tk()
control_tk.geometry("300x300")
canvas_tk.geometry("900x900")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
self.radius_var.trace_variable("w", self.on_change)
tk.Entry(control_tk, textvariable=self.radius_var).grid()
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the two tkinter windows
control_tk.mainloop()
canvas_tk.mainloop()
def on_change(self, *args):
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
50+self.radius_var.get(), 50+self.radius_var.get()),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel: # update the image
self.panel.configure(image=image)
self.panel.image = image
else: # if it's the first time initialize the panel
self.panel = tk.Label(canvas_tk, image=image)
self.panel.image = image
self.panel.grid(sticky="w")
Drawing()
回溯错误基本上是抱怨图片不存在
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 508, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 29, in on_change
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 510, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Value changed
Value changed
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 38, in on_change
self.panel = tk.Label(canvas_tk, image=image)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist
首先,你不应该使用多个Tk()
实例。其次,你最好不要在跟踪输入变化时使用 trace()
,在用户输入值并按下 Enter
键后使用 bind('<Return>', ...)
触发绘图。以下是基于您的修改后的代码:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
control_tk.geometry("300x300+800+600")
canvas_tk = tk.Toplevel() # use Toplevel instead of Tk
canvas_tk.geometry("900x900+10+10")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
entry = tk.Entry(control_tk, textvariable=self.radius_var)
entry.grid()
# binding Enter key on entry to trigger the drawing
entry.bind('<Return>', self.on_change)
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the main window
control_tk.mainloop()
def on_change(self, *args):
try:
radius = self.radius_var.get()
except:
print('Invalid number')
return
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-radius, 50-radius, 50+radius, 50+radius),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel:
self.panel.configure(image=image)
else:
self.panel = tk.Label(canvas_tk, image=image)
self.panel.grid(sticky='w')
self.panel.image = image
Drawing()
我想做一些应该相当简单的事情,但我正在努力让它发挥作用。
基本上我有 2 个 Tkinter windows(canvas_tk
和 control_tk
)。
在 canvas_tk
中,我想显示一张图片并在其上画一个圆圈。
在control_tk
中,我有一个输入要绘制的圆的半径的条目。
在我的代码中,关键行位于代码的最底部:
self.panel = tk.Label(canvas_tk, image=image)
如果我在 control_tk 中制作标签或者如果我不指定父级,它实际上可以正常工作并在 control_tk window 中绘制圆圈 但是我希望在 canvas_tk window
中绘制圆圈self.panel = tk.Label(image=image) # Works
self.panel = tk.Label(control_tk, image=image) # Works
self.panel = tk.Label(canvas_tk, image=image) # Fails
这是我的最小代码:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
canvas_tk = tk.Tk()
control_tk.geometry("300x300")
canvas_tk.geometry("900x900")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
self.radius_var.trace_variable("w", self.on_change)
tk.Entry(control_tk, textvariable=self.radius_var).grid()
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the two tkinter windows
control_tk.mainloop()
canvas_tk.mainloop()
def on_change(self, *args):
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
50+self.radius_var.get(), 50+self.radius_var.get()),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel: # update the image
self.panel.configure(image=image)
self.panel.image = image
else: # if it's the first time initialize the panel
self.panel = tk.Label(canvas_tk, image=image)
self.panel.image = image
self.panel.grid(sticky="w")
Drawing()
回溯错误基本上是抱怨图片不存在
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 508, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 29, in on_change
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 510, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Value changed
Value changed
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 38, in on_change
self.panel = tk.Label(canvas_tk, image=image)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist
首先,你不应该使用多个Tk()
实例。其次,你最好不要在跟踪输入变化时使用 trace()
,在用户输入值并按下 Enter
键后使用 bind('<Return>', ...)
触发绘图。以下是基于您的修改后的代码:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
control_tk.geometry("300x300+800+600")
canvas_tk = tk.Toplevel() # use Toplevel instead of Tk
canvas_tk.geometry("900x900+10+10")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
entry = tk.Entry(control_tk, textvariable=self.radius_var)
entry.grid()
# binding Enter key on entry to trigger the drawing
entry.bind('<Return>', self.on_change)
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the main window
control_tk.mainloop()
def on_change(self, *args):
try:
radius = self.radius_var.get()
except:
print('Invalid number')
return
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-radius, 50-radius, 50+radius, 50+radius),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel:
self.panel.configure(image=image)
else:
self.panel = tk.Label(canvas_tk, image=image)
self.panel.grid(sticky='w')
self.panel.image = image
Drawing()