【问题标题】:How to prevent image to fill entire Tkinter window while resizing?如何在调整大小时防止图像填满整个 Tkinter 窗口?
【发布时间】:2016-02-25 17:29:09
【问题描述】:

基于this answer,我想在主图像下方添加第二个小部件。

当用户调整此图像的大小时,图像旨在适合窗口。

参见@Marcin 的示例:

问题是,如果我在窗口中添加任何小部件,就会发生一些奇怪的事情(这里是文本):

图像逐渐增长,直到填满整个窗口,第二个小部件消失。

这是我的代码:

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()

我尝试使用不同的选项包装 imgtxt,但没有任何改变。

请问有人知道我做错了什么吗?

【问题讨论】:

  • 我敢打赌,这与 事件会在任何使窗口调整大小时触发的事实有关,而不仅仅是当用户拖动窗口句柄时。如果回调中的代码可以改变窗口大小,那么它可能会导致回调近乎连续地触发。

标签: python image python-3.x tkinter image-resizing


【解决方案1】:

在同一小部件​​上的 &lt;Configure&gt; 回调中调用小部件上的 .configure 很像递归,总是有永无止境的风险。

&lt;Configure&gt; 触发event.widthevent.height 时,会自动填充2 个像素,因此将图像设置为该大小会使Label 的大小增加4 个像素,再次触发&lt;Configure&gt; 事件。

这不会在example by @markus 中发生,因为一旦标签是具有强制几何形状的窗口的大小,它就不会再次重新配置,这也是图像完成消耗所有空间后程序中发生的情况在窗户上。

真正快速的解决办法是改变:

    new_width = event.width
    new_height = event.height

收件人:

    new_width = event.width - 4
    new_height = event.height - 4

为了补偿间距,但我绝对不保证它会始终如一地工作。


这是一个不同的实现,它使用Canvas 而不是FrameLabel

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")

这种方式不是重新配置小部件,而是在画布上重新绘制图像。

【讨论】:

  • 这很好用,非常感谢您的解释和解决方法!
猜你喜欢
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多