为什么此代码会自动使 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()