如何防止图像在调整大小时填满整个 Tkinter window?
How to prevent image to fill entire Tkinter window while resizing?
基于this answer,我想在主图下方添加第二个小部件。
当用户调整这幅图像的大小时,该图像旨在适应 window。
参见@Marcin 的示例:
问题是,如果我向 window 添加任何小部件,就会发生一些奇怪的事情(此处带有文本):
图像逐渐变大,直到填满整个 window,然后第二个小部件消失。
这是我的代码:
from tkinter import *
from PIL import Image, ImageTk
from io import BytesIO
import base64
root = Tk()
root.title("Title")
root.geometry("600x600")
class ImageFrame(Frame):
def __init__(self, master, *pargs):
Frame.__init__(self, master, *pargs)
self.black_pixel = BytesIO(base64.b64decode("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="))
self.image = Image.open(self.black_pixel)
self.img_copy= self.image.copy()
self.background_image = ImageTk.PhotoImage(self.image)
self.background = Label(self, image=self.background_image)
self.background.pack(fill=BOTH, expand=YES)
self.background.bind('<Configure>', self._resize_image)
self.width = 1
self.height = 1
def _resize_image(self,event):
new_width = event.width
new_height = event.height
if new_width != self.width or new_height != self.height:
self.width = new_width
self.height = new_height
self.image = self.img_copy.resize((new_width, new_height))
self.background_image = ImageTk.PhotoImage(self.image)
self.background.configure(image = self.background_image)
img = ImageFrame(root)
txt = Text(root)
img.pack(fill=BOTH, expand=YES)
txt.pack()
root.mainloop()
我尝试用不同的选项打包 img
和 txt
,但没有任何改变。
有人知道我做错了什么吗?
从同一个小部件的 <Configure>
回调中调用一个小部件的 .configure
很像递归,总是有永无止境的风险。
当 <Configure>
触发 event.width
并且 event.height
包含 2 个像素的自动填充时,因此将图像设置为该大小会增加 Label
的大小4 个像素再次触发 <Configure>
事件。
这不会在 example by @markus 中发生,因为一旦 Label 的大小与 window 的大小相同且具有强制几何形状,它就不会再次重新配置,这也是您的程序中发生的一次图像已消耗完 window.
上的所有 space
真正快速的解决方法是更改:
new_width = event.width
new_height = event.height
收件人:
new_width = event.width - 4
new_height = event.height - 4
为了补偿间距,但我绝对不保证它会始终如一地工作。
这是一个不同的实现,它使用 Canvas
而不是 Frame
和 Label
:
class ImageFrame(Canvas):
def __init__(self, master, *pargs ,**kw):
Canvas.__init__(self, master, *pargs,**kw)
self.black_pixel = BytesIO(base64.b64decode("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="))
self.img_copy = Image.open(self.black_pixel)
self.image = None #this is overriden every time the image is redrawn so there is no need to make it yet
self.bind("<Configure>",self._resize_image)
def _resize_image(self,event):
origin = (0,0)
size = (event.width, event.height)
if self.bbox("bg") != origin + size:
self.delete("bg")
self.image = self.img_copy.resize(size)
self.background_image = ImageTk.PhotoImage(self.image)
self.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
self.tag_lower("bg","all")
这种方式不是重新配置小部件,而是重新绘制 canvas 上的图像。
基于this answer,我想在主图下方添加第二个小部件。
当用户调整这幅图像的大小时,该图像旨在适应 window。
参见@Marcin 的示例:
问题是,如果我向 window 添加任何小部件,就会发生一些奇怪的事情(此处带有文本):
图像逐渐变大,直到填满整个 window,然后第二个小部件消失。
这是我的代码:
from tkinter import *
from PIL import Image, ImageTk
from io import BytesIO
import base64
root = Tk()
root.title("Title")
root.geometry("600x600")
class ImageFrame(Frame):
def __init__(self, master, *pargs):
Frame.__init__(self, master, *pargs)
self.black_pixel = BytesIO(base64.b64decode("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="))
self.image = Image.open(self.black_pixel)
self.img_copy= self.image.copy()
self.background_image = ImageTk.PhotoImage(self.image)
self.background = Label(self, image=self.background_image)
self.background.pack(fill=BOTH, expand=YES)
self.background.bind('<Configure>', self._resize_image)
self.width = 1
self.height = 1
def _resize_image(self,event):
new_width = event.width
new_height = event.height
if new_width != self.width or new_height != self.height:
self.width = new_width
self.height = new_height
self.image = self.img_copy.resize((new_width, new_height))
self.background_image = ImageTk.PhotoImage(self.image)
self.background.configure(image = self.background_image)
img = ImageFrame(root)
txt = Text(root)
img.pack(fill=BOTH, expand=YES)
txt.pack()
root.mainloop()
我尝试用不同的选项打包 img
和 txt
,但没有任何改变。
有人知道我做错了什么吗?
从同一个小部件的 <Configure>
回调中调用一个小部件的 .configure
很像递归,总是有永无止境的风险。
当 <Configure>
触发 event.width
并且 event.height
包含 2 个像素的自动填充时,因此将图像设置为该大小会增加 Label
的大小4 个像素再次触发 <Configure>
事件。
这不会在 example by @markus 中发生,因为一旦 Label 的大小与 window 的大小相同且具有强制几何形状,它就不会再次重新配置,这也是您的程序中发生的一次图像已消耗完 window.
上的所有 space真正快速的解决方法是更改:
new_width = event.width
new_height = event.height
收件人:
new_width = event.width - 4
new_height = event.height - 4
为了补偿间距,但我绝对不保证它会始终如一地工作。
这是一个不同的实现,它使用 Canvas
而不是 Frame
和 Label
:
class ImageFrame(Canvas):
def __init__(self, master, *pargs ,**kw):
Canvas.__init__(self, master, *pargs,**kw)
self.black_pixel = BytesIO(base64.b64decode("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="))
self.img_copy = Image.open(self.black_pixel)
self.image = None #this is overriden every time the image is redrawn so there is no need to make it yet
self.bind("<Configure>",self._resize_image)
def _resize_image(self,event):
origin = (0,0)
size = (event.width, event.height)
if self.bbox("bg") != origin + size:
self.delete("bg")
self.image = self.img_copy.resize(size)
self.background_image = ImageTk.PhotoImage(self.image)
self.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
self.tag_lower("bg","all")
这种方式不是重新配置小部件,而是重新绘制 canvas 上的图像。