I know that it is a recurring theme in the English forum, but no matter how much I have read, studied and tried, I am not able to find and fix the problem.
It is that when I resize the window vertically with the mouse, the corresponding part of the canvas does not appear.
A loop resizing issue is repeatedly cited due to the highlightthickness parameter causing it to loop. My problem is that either it goes into a loop or it doesn't seem to react.
An image, notImage.800x540.png, is used , which must be in the execution directory.
y este el programa:
import tkinter as tk
from tkinter import ttk, font
from PIL import Image, ImageTk
IMAGENESPORFILA = 3
class Cuadro(tk.Canvas):
def __init__(self, master, imgpath, basewidth=250, *args, **kwargs):
super().__init__(master , *args, **kwargs)
self.master = master
self.imgpath = imgpath
self.configure(highlightthickness=0, bg="red") # sin borde
if not imgpath:
self.imgpath = ".\\bigblue.png"
self.original = Image.open(self.imgpath) # pasa a formato PIL
width1, height = self.original.size
# Reducir imagen a anchura necesaria
# basewidth = 300 # -------------------------------------------------------- Restablecer
self.basewidth = basewidth
wpercent = (basewidth/float(self.original.size[0]))
hsize = int((float(self.original.size[1])*float(wpercent)))
self.thumbnail = self.original.resize((basewidth, hsize), Image.ANTIALIAS)
# presenta imagen redimensionada (thumbnail)
self.pimagen = ImageTk.PhotoImage(self.thumbnail)
self.create_image(0, 0, image= self.pimagen, anchor='nw', tags='image')
self.update_idletasks()
bbox =self.bbox(tk.ALL)
self.config(width=bbox[2] - bbox[0], height=bbox[3] - bbox[1])
self.grid(row=0, column=0)
class GUI(tk.Frame):
def __init__(self, master, pathdir, *args, **kwargs):
super().__init__(master, *args, **kwargs)
# Crear Canvas para contener imagenes y scrollbars
canvas = tk.Canvas(self, background="royal blue")
canvas.configure(highlightthickness=0) # independizado para probar distintas opciones
canvas.grid(column=0, row=0, sticky="nsew")
# Create a vertical scrollbar linked to the canvas.
vsbar = tk.Scrollbar(self, orient=tk.VERTICAL, command=canvas.yview)
vsbar.grid(row=0, column=1, sticky=tk.NS)
canvas.configure(yscrollcommand=vsbar.set)
# Create a horizontal scrollbar linked to the canvas.
hsbar = tk.Scrollbar(self, orient=tk.HORIZONTAL, command=canvas.xview)
hsbar.grid(row=1, column=0, sticky=tk.EW)
canvas.configure(xscrollcommand=hsbar.set)
# Create a frame on the canvas to contain the images.
image_frame = tk.Frame(canvas, bg="Green", bd=2)
arr_jpg = ["./noImagen.800x540.png"]*5
total = len(arr_jpg)
for r in range (total//IMAGENESPORFILA + 1):
for c in range(min(IMAGENESPORFILA, total-r*IMAGENESPORFILA)):
Cuadro(image_frame, arr_jpg[r*IMAGENESPORFILA+c]).grid(column=c, row=r)
# Create canvas window to hold the image_frame.
canvas.create_window((0,0), window=image_frame, anchor=tk.NW)
# tag all of the drawn widgets
canvas.addtag_all("all")
image_frame.update_idletasks() # Needed to make bbox info available.
bbox = canvas.bbox(tk.ALL) # Get bounding box of canvas with Images.
w, h = bbox[2]-bbox[1], bbox[3]-bbox[1]
canvas.configure(scrollregion=bbox, width=w)
# ******************* Para hacer las variables accesibles por el evento ********************
self.canvas = canvas
self.bbox = bbox
self.canvas.bind("<Configure>", self.onCanvasConfigure)
# ***************************************
self.grid(row=0, column=0, sticky = "nsew")
def onCanvasConfigure(self, event):
# height is tweaked to account for window borders
height = event.height
# self.canvas.configure(scrollregion=self.bbox, height=height-4)
self.canvas.configure(scrollregion=self.bbox, height=height)
if __name__ == "__main__":
root = tk.Tk()
GUI(root,"no_se_usa!")
root.mainloop()
What should I correct?
The problem is that neither tu
Frame
nor tuCanvas
expand or contract depending on the size of their respective parents, they have a fixed initial size and continue with that redemption or not of the window. You must add a weight greater than 0 to the row of both the parent and parent windowsFrame
:It is very important that you do this before the da call
bbox
and assign the initial size if you leave the default height (as is your case) or the default width (which in your case if you specify it,width=w
), otherwise it will enter an infinite loop with iterative calls toonCanvasConfigure
.A couple more observations:
Passing the height in
onCanvasConfigure
the methodconfigure
is not an error, but it is redundant. The height that the event provides is the one that the canvas has, therefore we do not modify anything with it, we pass the same value that it already has. You can check it very simply with:In the method bound to the event
Configure
you really have to callcanvas.bbox
each time :canvas.configure(scrollregion=bbox, width=w)
If your canvas doesn't change content after being created and nothing happens when calling in the initializer, itbbox
is always the same, but in that case we don't need to bind the event or the function. Try to leave the methodonCanvasConfigure
with only onepass
and comment the rest of the lines and you will realize that everything remains the same...Now if items are added, removed or resized within the canvas after this its bbox changes and so we need to update the scroll region to take it into account.
self.bbox
is a static value that is the bbox of the canvas in the__init__
, if later the bbox of the canvas changes itself.bbox
will continue with its initial value and the scrool region will not be modified.Therefore, if you expect the internal content of the canvas to change, you should do:
To avoid the loop caused by the border, you can use
highlightthickness=0
or also for that particular case you can just callupdate_idletasks
the inner frame again right after the call toconfigure
adjust the initial size: