Reputation: 2200
Either I did misread some of the documentation or I still do not quite understand some concepts of Tkinter.
If I add widgets (e.g. Labels) to a frame using grid()
the frame gets resized to fit them. (so far as expected)
If I call grid_remove on all the children (using frame.winfo_children()
to adress all of them) the frame does not get resized again (what I would like to have).
Is there any specific reason why after these actions
grid_remove()
all of themthese results occur?
I am using an extension of this code (which is more than the MCVE
) to collapse
or expand
a ttk.LabelFrame
triggered by click onto the Label. (Thus hiding the children with the intention of keeping subsequent .grid()
calls without parameters available).
Possibly I am running on an inefficient approach here - remarks on that are welcome as well.
@TheLizzards approach of rescaling the frame to 1 and then to 0 does not really work in this case (The Label of the LabelFrame disappears) but I do quite like the approach.
@JRiggles approach works with the given restraints but is quite ugly when elements are added to the collapsed Labelframe.
At the current stage I did play around using both approaches, already tried @BryanOakleys answer that I did see in a different post but it seems me binding '<Expose>'
resulted in an infinityloop.
Replication Code:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
app = ttk.Frame(root)
app.grid(row=0, column=0, columnspan=2, sticky=tk.NW+tk.SE)
def add(start=None):
start = start or len(app.winfo_children())
for i in range(start,start+10):
ttk.Label(app, text=f"{i}").grid(row=i, column=0, sticky=tk.NW+tk.SE)
def rem():
for _f in app.grid_slaves():
_f.grid_remove()
ttk.Button(root, text='+', command=add).grid(row=1, column=0)
ttk.Button(root, text='-', command=rem).grid(row=1, column=1)
root.mainloop()
Upvotes: -1
Views: 61
Reputation: 386315
The issue is that grid
(and also pack
) is responsible for resizing the window when the window has child widgets. When you remove the last widget, grid
is no longer responsible for resizing the window so it doesn't cause the window to resize.
A simple solution is to create a 1x1 pixel widget (for example, a frame) and add it with grid
and the window will shrink around it.
Upvotes: 0
Reputation: 47085
You can call app.grid_remove()
at the end of rem()
to make frame app
invisible. But you need to call app.grid()
at the end of add()
to show it back.
Note that it is better to call _f.destroy()
instead of _f.grid_remove()
if you will not resume those labels later.
def add(start=None):
start = start or len(app.winfo_children())
for i in range(start,start+10):
ttk.Label(app, text=f"{i}").grid(row=i, column=0, sticky=tk.NW+tk.SE)
app.grid()
def rem():
for _f in app.grid_slaves():
_f.destroy()
app.grid_remove()
Upvotes: 1
Reputation: 7710
This is a known issue in tcl
. The best workaround is to either destroy the frame and recreate it or use:
app.config(width=1, height=1)
app.config(width=0, height=0)
This sets the width and height to 1 pixel and then resets it so that it can auto-resize when more widgets are added. For a full solution, we will have to wait for someone to fix this behaviour in tcl
.
Upvotes: 3
Reputation: 6810
I was able to get the Frame
to collapse on item removal by adding a call to app.update_idletasks()
in the rem
function, but the behavior is a bit janky because it's being called on every iteration of the for
loop, and it does seem to leave "space" for an empty row in the Frame
(and no, moving it outside the for
loop doesn't work, alas)
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
app = ttk.Frame(root)
app.grid(row=0, column=0, columnspan=2, sticky='nesw')
def add(start=None):
start = start or len(app.winfo_children())
for i in range(start,start+10):
ttk.Label(app, text=f"{i}").grid(row=i, column=0, sticky='nesw')
def rem():
for _f in app.grid_slaves():
_f.grid_remove()
app.update_idletasks()
ttk.Button(root, text='+', command=add).grid(row=1, column=0)
ttk.Button(root, text='-', command=rem).grid(row=1, column=1)
root.mainloop()
I can't say I recommend this approach, but it "works"
Upvotes: 0