为什么此代码会自动使 Tkinter window 连续 resize/grow?
Why does this code make the Tkinter window continuously resize/grow automatically?
本应使用 window 调整图像标签的大小,但整个 window(连同图像)会自行调整大小。
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width=500)
canvas.pack()
from PIL import Image, ImageTk
def resize_image(event):
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.configure(image = photo)
label.image = photo
image = Image.open("*file path to image*")
copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
label = tk.Label(canvas, image=photo)
label.bind('<Configure>', resize_image)
label.pack(fill='both', expand='yes')
root.mainloop()
每当小部件改变大小时,您正在调用一个函数。在该函数中,您正在将图像大小调整为标签的大小。但是,图像周围可能有边框或填充,因此这会导致标签略微增大。由于标签增长,它会触发 <Configure>
事件再次调整图像大小,这会导致标签更改大小,这会触发 <Configure>
事件再次调整图像大小,从而导致标签更改大小, ....
解决方案是确保 borderwidth 和 highlightthickness 为零,and/or 将图像大小调整为比标签小几个像素,这样您就不会强制标签变大。
好的,经过一些测试,我想我已经找到了您正在寻找的解决方案。
我们可以将标签放在框架中,然后调整框架的大小以匹配 canvas 大小,而不是将标签放在 canvas 上。同时我们可以调整标签中的图像大小,即使它比框架略大,它会触发另一个调整大小,直到您直接调整 window。
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width=500)
canvas.pack(fill='both', expand=True)
frame = tk.Frame(canvas)
canvas.create_window((0, 0), anchor='nw', window=frame, tags='my_frame')
def resize_image(event):
canvas.itemconfigure("my_frame", width=event.width, height=event.height)
image = copy_of_image.resize((event.width, event.height ))
photo = ImageTk.PhotoImage(image)
label.configure(image=photo)
label.image = photo
image = Image.open("*file path to image*")
copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
label = tk.Label(frame, image=photo)
label.pack(fill='both', expand=True)
canvas.bind('<Configure>', resize_image)
root.mainloop()
OOP 解决方案见下文:
import tkinter as tk
from PIL import Image, ImageTk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.canvas = tk.Canvas(self)
self.frame = tk.Frame(self.canvas)
self.canvas.pack(fill='both', expand=True)
image = Image.open('./Images/green.png')
self.copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
self.label = tk.Label(self.frame, image=photo)
self.label.pack(fill='both', expand=True)
self.label.image = photo
self.canvas.create_window((0, 0), anchor='nw', window=self.frame, tags='my_frame')
self.canvas.bind("<Configure>", self.on_canvas_configure)
def on_canvas_configure(self, event):
self.canvas.itemconfigure("my_frame", width=event.width, height=event.height)
image = self.copy_of_image.resize((event.width, event.height))
photo = ImageTk.PhotoImage(image)
self.label.configure(image=photo)
self.label.image = photo
if __name__ == "__main__":
App().mainloop()
本应使用 window 调整图像标签的大小,但整个 window(连同图像)会自行调整大小。
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width=500)
canvas.pack()
from PIL import Image, ImageTk
def resize_image(event):
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.configure(image = photo)
label.image = photo
image = Image.open("*file path to image*")
copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
label = tk.Label(canvas, image=photo)
label.bind('<Configure>', resize_image)
label.pack(fill='both', expand='yes')
root.mainloop()
每当小部件改变大小时,您正在调用一个函数。在该函数中,您正在将图像大小调整为标签的大小。但是,图像周围可能有边框或填充,因此这会导致标签略微增大。由于标签增长,它会触发 <Configure>
事件再次调整图像大小,这会导致标签更改大小,这会触发 <Configure>
事件再次调整图像大小,从而导致标签更改大小, ....
解决方案是确保 borderwidth 和 highlightthickness 为零,and/or 将图像大小调整为比标签小几个像素,这样您就不会强制标签变大。
好的,经过一些测试,我想我已经找到了您正在寻找的解决方案。
我们可以将标签放在框架中,然后调整框架的大小以匹配 canvas 大小,而不是将标签放在 canvas 上。同时我们可以调整标签中的图像大小,即使它比框架略大,它会触发另一个调整大小,直到您直接调整 window。
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width=500)
canvas.pack(fill='both', expand=True)
frame = tk.Frame(canvas)
canvas.create_window((0, 0), anchor='nw', window=frame, tags='my_frame')
def resize_image(event):
canvas.itemconfigure("my_frame", width=event.width, height=event.height)
image = copy_of_image.resize((event.width, event.height ))
photo = ImageTk.PhotoImage(image)
label.configure(image=photo)
label.image = photo
image = Image.open("*file path to image*")
copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
label = tk.Label(frame, image=photo)
label.pack(fill='both', expand=True)
canvas.bind('<Configure>', resize_image)
root.mainloop()
OOP 解决方案见下文:
import tkinter as tk
from PIL import Image, ImageTk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.canvas = tk.Canvas(self)
self.frame = tk.Frame(self.canvas)
self.canvas.pack(fill='both', expand=True)
image = Image.open('./Images/green.png')
self.copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
self.label = tk.Label(self.frame, image=photo)
self.label.pack(fill='both', expand=True)
self.label.image = photo
self.canvas.create_window((0, 0), anchor='nw', window=self.frame, tags='my_frame')
self.canvas.bind("<Configure>", self.on_canvas_configure)
def on_canvas_configure(self, event):
self.canvas.itemconfigure("my_frame", width=event.width, height=event.height)
image = self.copy_of_image.resize((event.width, event.height))
photo = ImageTk.PhotoImage(image)
self.label.configure(image=photo)
self.label.image = photo
if __name__ == "__main__":
App().mainloop()