2016-02-25 69 views
2

基于this answer,我想在主图像下面添加第二个小部件。如何防止图像在调整大小时填充整个Tkinter窗口?

当用户调整大小时,该图像适合窗口。

请参阅从@Marcin的例子:

Resized image

的问题是,如果我添加任何到窗口,奇怪的事情发生了(这里用文字):

Weird resizing

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

这里是我的代码:

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有不同的选择,但它chnanged什么。

有没有人有我的做法错误的想法,请?

+3

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

回答

1

在同一个窗口小部件上从<Configure>回调调用.configure很像递归,总会有永不结束的风险。

<Configure>触发event.widthevent.height包括的2个像素的自动填充,所以设置图像到规定大小增加Label由4个像素再次烧制<Configure>事件的大小。

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

真正快速修复方法是:

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

这种方式,而不是重新配置它只是重绘的画布上的图像的部件。

+0

这很好,非常感谢你的解释和解决方法! – Delgan

相关问题