Why is the Scrollbar not working? - python

THis is my code for TKinter GUI:
from tkinter import *;
from tkinter import ttk
# import tix as tk
class pryprotclass:
def onFrameConfigure(self, event,canvas1):
canvas1.configure(scrollregion=canvas1.bbox("all"))
def __init__(self,master):
frame2=Frame(master);
frame2.configure(background='yellow')
frame2.pack_propagate(False) ;
frame2.pack(fill="both", expand=True,side=RIGHT);
canvas1 = Canvas(frame2, borderwidth=0, background="#ffffff")
canvas1.configure(scrollregion=canvas1.bbox("all"))
frame3=Frame(canvas1);
vsb = Scrollbar(frame3, orient="vertical", command=canvas1.yview)
canvas1.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas1.pack(side="left", fill="both", expand=True)
canvas1.create_window((4,4), window=frame3, anchor="nw")
canvas1.configure(scrollregion=canvas1.bbox("all"))
frame3.bind("<Configure>"),
canvas1.configure(scrollregion=canvas1.bbox("all"))
frame3.config( width=240 );
frame3.configure(background='purple')
frame3.pack_propagate(False) ;
now there are around 40 labels now to they take up the entire y direction
See image--https://imgur.com/Epq6vJJ
What is the error in the code?
Neither is the scrollbar working nor am I able to see the bar in the scrollbar to move up or down?
here is the requested code (unneccessary)
label=Label(frame3,text='ALL TASKS')
label.configure(background="WHITE",font="Courier 14 bold")
label.pack(side=TOP,anchor="nw",padx=10,pady=10)
chromelogo=PhotoImage(file="./Images/chrome.gif")
chromelogo=chromelogo.subsample(16,16)
labelchrome=Label(frame3,text="Chrome")
labelchrome.config(image=chromelogo)
labelchrome.config(background='WHITE')
labelchrome.config(compound='left')
labelchrome.image=chromelogo
labelchrome.pack(side=TOP,anchor="nw")
c1=Checkbutton(frame3,text="History")
c2=Checkbutton(frame3,text="Cookies")
c3=Checkbutton(frame3,text="Saved Passwords")
c4=Checkbutton(frame3,text="Download History")
c5=Checkbutton(frame3,text="Last Download Location")
c1.config(background='WHITE')
c2.config(background='WHITE')
c3.config(background='WHITE')
c4.config(background='WHITE')
c5.config(background='WHITE')
c1.pack(anchor="nw",padx=30)
c2.pack(anchor="nw",padx=30)
c3.pack(anchor="nw",padx=30)
c4.pack(anchor="nw",padx=30)
c5.pack(anchor="nw",padx=30)
firefoxlogo=PhotoImage(file="./Images/firefox.gif")
firefoxlogo=firefoxlogo.subsample(18,18)
labelfirefox=Label(frame3,text="Firefox")
labelfirefox.config(background='WHITE')
labelfirefox.config(image=firefoxlogo)
labelfirefox.config(compound='left')
labelfirefox.image=firefoxlogo
labelfirefox.pack(side=TOP,anchor="nw")
c6=Checkbutton(frame3,text="History")
c7=Checkbutton(frame3,text="Cookies")
c8=Checkbutton(frame3,text="Saved Passwords")
c9=Checkbutton(frame3,text="Internet Cache")
c10=Checkbutton(frame3,text="Saved Form Information")
c6.config(background='WHITE')
c7.config(background='WHITE')
c8.config(background='WHITE')
c9.config(background='WHITE')
c10.config(background='WHITE')
c6.pack(anchor="nw",padx=30)
c7.pack(anchor="nw",padx=30)
c8.pack(anchor="nw",padx=30)
c9.pack(anchor="nw",padx=30)
c10.pack(anchor="nw",padx=30)
iexplorelogo=PhotoImage(file="./Images/iexplore.gif")
iexplorelogo=iexplorelogo.subsample(12,12)
labeliexplore=Label(frame3,text="Internet Explorer")
labeliexplore.config(image=iexplorelogo)
labeliexplore.config(background='WHITE')
labeliexplore.config(compound='left')
labeliexplore.image=iexplorelogo
labeliexplore.pack(side=TOP,anchor="nw")
c11=Checkbutton(frame3,text="History")
c12=Checkbutton(frame3,text="Cookies")
c13=Checkbutton(frame3,text="Last Download Location")
c14=Checkbutton(frame3,text="Temporary Internet Files")
c15=Checkbutton(frame3,text="Autocomplete Form History")
c11.config(background='WHITE')
c12.config(background='WHITE')
c13.config(background='WHITE')
c14.config(background='WHITE')
c15.config(background='WHITE')
c11.pack(anchor="nw",padx=30)
c12.pack(anchor="nw",padx=30)
c13.pack(anchor="nw",padx=30)
c14.pack(anchor="nw",padx=30)
c15.pack(anchor="nw",padx=30)
explorerlogo=PhotoImage(file="./Images/explorer.gif")
explorerlogo=explorerlogo.subsample(16,16)
explorerlabel=Label(frame3,text="Windows Explorer")
explorerlabel.config(image=explorerlogo)
explorerlabel.config(background='WHITE')
explorerlabel.config(compound='left')
explorerlabel.image=explorerlogo
explorerlabel.pack(side=TOP,anchor="nw")
c16=Checkbutton(frame3,text="Recent Documents")
c17=Checkbutton(frame3,text="Run(in Start Menu)")
c18=Checkbutton(frame3,text="Network Passwords")
c16.config(background='WHITE')
c17.config(background='WHITE')
c18.config(background='WHITE')
c16.pack(anchor="nw",padx=30)
c17.pack(anchor="nw",padx=30)
c18.pack(anchor="nw",padx=30)
systemlogo=PhotoImage(file="./Images/system.gif")
systemlogo=systemlogo.subsample(16,16)
systemlabel=Label(frame3,text="System")
systemlabel.config(image=systemlogo)
systemlabel.config(background='WHITE')
systemlabel.config(compound='left')
systemlabel.image=systemlogo
systemlabel.pack(side=TOP,anchor="nw")
c19=Checkbutton(frame3,text="Recycle Bin")
c20=Checkbutton(frame3,text="Temporary Files")
c21=Checkbutton(frame3,text="Clipboard")
c22=Checkbutton(frame3,text="DNS Cache")
#c23=Checkbutton(frame3,text="add")
c19.config(background='WHITE')
c20.config(background='WHITE')
c21.config(background='WHITE')
c22.config(background='WHITE')
c19.pack(anchor="nw",padx=30)
c20.pack(anchor="nw",padx=30)
c21.pack(anchor="nw",padx=30)
c22.pack(anchor="nw",padx=30)
frame3.pack(fill="y", expand=False,side="left");
frame4=Frame(frame2);
frame4.configure(background='PINK')
frame4.pack_propagate(False) ;
frame5=Frame(frame4)
frame5.configure(background='green')
progressbar=ttk.Progressbar(frame4,orient=HORIZONTAL)
progressbar.pack(fill=BOTH,padx=20,pady=15)
run_PryPro=Button(frame4,text="RUN")
frame5.configure(height=300)
frame5.pack(fill=BOTH,expand=True,padx=20)
run_PryPro.pack(padx=60,pady=25,ipadx=20,ipady=10)
frame4.packfill="both", expand=True,side="right");
main Class's Code as requested ==
from tkinter import * ;
from lefttoolbar import *;
from pyprot import *;
from logotop import *;
root=Tk()
obj_pryprot=pryprotclass(root);
=root.minsize(800, 500);
root.mainloop();

You need to be more methodical in writing your code. I count at least nine bugs in your code. You need to start by creating as few widgets as possible, and then add features only when you know the existing features are working correctly. It's very difficult to debug eight things at once.
Here are the things that need fixing:
PEP8 recommends that class names begin with an uppercase character
You need to remove frame3.pack_propagate(False). Turning off geometry propagation is an advanced feature that you almost never should use.
You need to remove frame2.pack_propagate(False)
You need to make the scrollbar a child of frame2, not frame3, since frame3 is what you want to scroll. As a general rules, scrollbars and the things they scroll should have the same parent/master
You need to give the canvas a size
you need to make canvas1 be an instance variable
Your bind needs to associate a function with the event
The bound function needs to take a single argument
The bound function needs to use self.canvas1 rather than canvas1
Here's a version of your code with all of those issues fixed:
from tkinter import *;
class Pryprotclass:
def onFrameConfigure(self, event):
self.canvas1.configure(scrollregion=self.canvas1.bbox("all"))
def __init__(self,master):
frame2=Frame(master);
frame2.pack(fill="both", expand=True, side=RIGHT);
self.canvas1 = Canvas(frame2, borderwidth=0, background="#ffffff")
vsb = Scrollbar(frame2, orient="vertical", command=self.canvas1.yview)
self.canvas1.configure(yscrollcommand=vsb.set)
self.canvas1.pack(side="left", fill="both", expand=True)
vsb.pack(side="right", fill="y")
frame3=Frame(self.canvas1);
self.canvas1.create_window((4,4), window=frame3, anchor="nw")
frame3.bind("<Configure>", self.onFrameConfigure),
# dummy widgets for testing
for i in range(100):
label = Label(frame3, text="Item #%s" % i)
label.pack(side="top", fill="x", padx=10, pady=1)
root = Tk()
p = Pryprotclass(root)
root.mainloop()

Related

Python - Tkinter frame's Configure event constantly firing, callback constantly being called

I am fairly new to Tkinter and am trying to build an application that contains table data within a scrollable canvas. I have designed a Table class that contains a Canvas widget, which in turn contains a Frame that contains the table content.
However, when trying to make the Canvas scroll-able, I am running into an issue. I have bound the table content's Configure event to a callback that sets the scroll region. However, when I run my application this callback is called forever in an infinite loop, and I am not sure why. I cannot figure out why the Configure event would be constantly firing.
Moreover, when trying to switch between tabs, my app will freeze, presumably because of the app being stuck in a loop of callback calls.
Below is a simplified example of what I am trying to do in my app. Can anyone help me figure out how to fix this problem, while also allowing the table content to be scroll-able?
import tkinter as tk
from tkinter import ttk
class Table(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent)
self.table_canvas = tk.Canvas(self, bg='cyan')
table_scrollbar = ttk.Scrollbar(
self.table_canvas,
orient='vertical',
command=self.table_canvas.yview)
self.table_content = ttk.Frame(self.table_canvas)
self.table_content.bind('<Configure>', self.on_configure)
self.table_canvas.create_window(
(0, 0),
window=self.table_content,
anchor='nw')
self.table_canvas.configure(yscrollcommand=table_scrollbar.set)
for _ in range(10):
table_row = ttk.Frame(self.table_content)
ttk.Label(
table_row,
text='left text'
).grid(column=0, row=0, sticky='w')
ttk.Label(
table_row,
text='right text'
).grid(column=1, row=0, sticky='e')
table_row.columnconfigure(0, weight=1, uniform='same')
table_row.columnconfigure(1, weight=1, uniform='same')
table_row.pack(fill='x')
self.table_canvas.pack(side='left', fill='both', expand=True)
table_scrollbar.pack(side='right', fill='y')
def on_configure(self, event):
print('on configure triggered')
self.table_canvas.configure(scrollregion=self.table_canvas.bbox('all'))
app = tk.Tk()
app.geometry('600x600')
notebook = ttk.Notebook(app)
tab1 = ttk.Frame(notebook)
tab2 = ttk.Frame(notebook)
container1 = ttk.Frame(tab1)
label_container1 = ttk.Frame(container1)
ttk.Label(label_container1, text='Tab One').pack(side='left')
label_container1.pack(fill='x')
table1 = Table(container1)
table1.pack(fill='both', expand=True)
container1.pack(fill='both', expand=True)
container2 = ttk.Frame(tab2)
label_container2 = ttk.Frame(container2)
ttk.Label(label_container2, text='Tab Two').pack(side='left')
label_container2.pack(fill='x')
table2 = Table(container2)
table2.pack(fill='both', expand=True)
container2.pack(fill='both', expand=True)
notebook.add(tab1, text='One')
notebook.add(tab2, text='Two')
notebook.pack(fill='both', expand=True)
app.mainloop()
I'm not 100% sure of why this is happening, but the root cause seems to be that you're putting the scrollbar inside the canvas. As a rule of thumb, a scrollbar shouldn't be a child of the thing that it is scrolling.
If you move the scrollbar to be a child of the frame (self) instead of the canvas, the problem goes away.
table_scrollbar = ttk.Scrollbar(
self,
orient='vertical',
command=self.table_canvas.yview)

How to shrink a frame in tkinter after removing contents?

Most of the topics I came across deals with how to not shrink the Frame with contents, but I'm interested in shrinking it back after the destruction of said contents. Here's an example:
import tkinter as tk
root = tk.Tk()
lbl1 = tk.Label(root, text='Hello!')
lbl1.pack()
frm = tk.Frame(root, bg='black')
frm.pack()
lbl3 = tk.Label(root, text='Bye!')
lbl3.pack()
lbl2 = tk.Label(frm, text='My name is Foo')
lbl2.pack()
So far I should see this in my window:
Hello!
My name is Foo
Bye!
That's great, but I want to keep the middle layer interchangeable and hidden based on needs. So if I destroy the lbl2 inside:
lbl2.destroy()
I want to see:
Hello!
Bye!
But what I see instead:
Hello!
███████
Bye!
I want to shrink frm back to basically non-existence because I want to keep the order of my main widgets intact. Ideally, I want to run frm.pack(fill=tk.BOTH, expand=True) so that my widgets inside can scale accordingly. However if this interferes with the shrinking, I can live without fill/expand.
I've tried the following:
pack_propagate(0): This actually doesn't expand the frame at all past pack().
Re-run frm.pack(): but this ruins the order of my main widgets.
.geometry(''): This only works on the root window - doesn't exist for Frames.
frm.config(height=0): Oddly, this doesn't seem to change anything at all.
frm.pack_forget(): From this answer, however it doesn't bring it back.
The only option it leaves me is using a grid manager, which works I suppose, but not exactly what I'm looking for... so I'm interested to know if there's another way to achieve this.
When you destroy the last widget within a frame, the frame size is no longer managed by pack or grid. Therefore, neither pack nor grid knows it is supposed to shrink the frame.
A simple workaround is to add a small 1 pixel by 1 pixel window in the frame so that pack still thinks it is responsible for the size of the frame.
Here's an example based off of the code in the question:
import tkinter as tk
root = tk.Tk()
lbl1 = tk.Label(root, text='Hello!')
lbl1.pack()
frm = tk.Frame(root, bg='black')
frm.pack()
lbl3 = tk.Label(root, text='Bye!')
lbl3.pack()
lbl2 = tk.Label(frm, text='My name is Foo')
lbl2.pack()
def delete_the_label():
lbl2.destroy()
if len(frm.winfo_children()) == 0:
tmp = tk.Frame(frm, width=1, height=1, borderwidth=0, highlightthickness=0)
tmp.pack()
root.update_idletasks()
tmp.destroy()
button = tk.Button(root, text="Delete the label", command=delete_the_label)
button.pack()
root.mainloop()
Question: Shrink a Frame after removing the last widget?
Bind to the <'Expose'> event and .configure(height=1) if no children.
Reference:
Expose
An Expose event is generated whenever all or part of a widget should be redrawn
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
tk.Label(self, text='Hello!').pack()
self.frm = frm = tk.Frame(self, bg='black')
frm.pack()
tk.Label(self, text='Bye!').pack()
tk.Label(frm, text='My name is Foo').pack()
self.menubar = tk.Menu()
self.config(menu=self.menubar)
self.menubar.add_command(label='delete', command=self.do_destroy)
self.menubar.add_command(label='add', command=self.do_add)
frm.bind('<Expose>', self.on_expose)
def do_add(self):
tk.Label(self.frm, text='My name is Foo').pack()
def do_destroy(self):
w = self.frm
if w.children:
child = list(w.children).pop(0)
w.children[child].destroy()
def on_expose(self, event):
w = event.widget
if not w.children:
w.configure(height=1)
if __name__ == "__main__":
App().mainloop()
Question: Re-run frm.pack(): but this ruins the order of my main widgets.
frm.pack_forget(), however it doesn't bring it back.
Pack has the options before= and after. This allows to pack a widget relative to other widgets.
Reference:
-before
Use its master as the master for the slaves, and insert the slaves just before other in the packing order.
Example using before= and self.lbl3 as anchor. The Frame are removed using .pack_forget() if no children and get repacked at the same place in the packing order.
Note: I show only the relevant parts!
class App(tk.Tk):
def __init__(self):
...
self.frm = frm = tk.Frame(self, bg='black')
frm.pack()
self.lbl3 = tk.Label(self, text='Bye!')
self.lbl3.pack()
...
def on_add(self):
try:
self.frm.pack_info()
except:
self.frm.pack(before=self.lbl3, fill=tk.BOTH, expand=True)
tk.Label(self.frm, text='My name is Foo').pack()
def on_expose(self, event):
w = event.widget
if not w.children:
w.pack_forget()
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

Tkinter: Too much space between label and button frame

I'm pretty new to Tkinter and I build a little window with different widgets.
My Code looks like this:
import tkinter as tk
from tkinter import ttk
class Application(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.master = master
self.master.geometry("800x600")
self.master.title("Tkinter Sandbox")
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(1, weight=1)
self._create_left_frame()
self._create_button_bar()
self._create_label_frame()
def _create_left_frame(self):
frame = tk.Frame(self.master, bg="red")
tree_view = ttk.Treeview(frame)
tree_view.column("#0", stretch=tk.NO)
tree_view.heading("#0", text="Treeview")
tree_view.pack(fill=tk.Y, expand=1)
frame.grid(row=0, column=0, rowspan=2, sticky=tk.N + tk.S)
def _create_button_bar(self):
frame = tk.Frame(self.master, bg="blue")
button_run_single = tk.Button(frame, text="Button 1")
button_run_all = tk.Button(frame, text="Button 2")
button_details = tk.Button(frame, text="Button 3")
button_run_single.grid(row=0, column=0)
button_run_all.grid(row=0, column=1, padx=(35, 35))
button_details.grid(row=0, column=2)
frame.grid(row=0, column=1, sticky=tk.N)
def _create_label_frame(self):
frame = tk.Frame(self.master, bg="blue")
name_label = tk.Label(frame, text="Label 1")
performance_label = tk.Label(frame, text="Label 2")
name_entry = tk.Entry(frame)
performance_entry = tk.Entry(frame)
name_label.grid(row=0, column=0)
name_entry.grid(row=0, column=1)
performance_label.grid(row=1, column=0)
performance_entry.grid(row=1, column=1)
frame.grid(row=1, column=1)
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
app.mainloop()
Between the three buttons and the label + entry frame is a huge space. I want the button and label + entry frame right under each other, without the huge space but the treeview should also expand vertically over the whole application window.
I think the problem might be my row and column configuration but I don't know how to solve this problem.
The way you've structured your code makes it hard to see the problem. As a good general rule of thumb, all calls to grid or pack for widgets within a single parent should be in one place. Otherwise, you create dependencies between functions that are hard to see and understand.
I recommend having each of your helper functions return the frame rather than calling grid on the frame. That way you give control to Application.__init__ for the layout of the main sections of the window.
For example:
left_frame = self._create_left_frame()
button_bar = self._create_button_bar()
label_frame = self._create_label_frame()
left_frame.pack(side="left", fill="y")
button_bar.pack(side="top", fill="x")
label_frame.pack(side="top", fill="both", expand=True)
I used pack here because it requires less code than grid for this type of layout. However, if you choose to switch to grid, or wish to add more widgets to the root window later, you only have to modify this one function rather than modify the grid calls in multiple functions.
Note: this requires that your functions each do return frame to pass the frame back to the __init__ method. You also need to remove frame.grid from each of your helper functions.
With just that simple change you end up with the button bar and label/entry combinations at the top of the section on the right. In the following screenshot I changed the background of the button_bar to green so you can see that it fills the top of the right side of the UI.
You need to change line
self.master.grid_rowconfigure(0, weight=1)
to
self.master.grid_rowconfigure(1, weight=1)
so that the second row takes all the space. Then you need to stick widgets from the label frame to its top by adding sticky parameter to the grid call in _create_label_frame:
frame.grid(row=1, column=1, sticky=tk.N)
I prefer to use the Pack Function since it gives a more open window - its easy to configure. When you use Pack() you can use labels with no text and just spaces to create a spacer, by doing this you won't run into the problem your facing.

Scrollbar disappears from Tkinter canvas, and refuses to adhere to side-packing

I am trying to attach a scrollbar to a Tkinter canvas.
To test the scrollbar, I dynamically generated 100 "Hello World" labels, and packed these inside a content-holding frame.
My code fails. Issues:
The scrollbar does not even appear.
The content frame instead expands to the full height of the 100-packed labels.
Interestingly, the scrollbar magically reappears if I shift self.frame_for_content.pack() under self.scrollbar.pack(). (Why this is so is beyond me, but the scrollbar still does not work or adhere to the side packing behaviour either.)
I have attempted to incorporate some of Brian Oakley's suggestions on scroll region and bbox, to no avail.
I have reduced the code to the bare minimum, but am unable to push through. Would appreciate the help.
import tkinter as tk
import tkinter.ttk as ttk
class TestGUI(tk.Tk):
def __init__(self):
super().__init__()
self.canvas = tk.Canvas(self)
self.frame_for_content = tk.Frame(self.canvas)
self.canvas_frame = self.canvas.create_window((0,0), window=self.frame_for_content, anchor=tk.NW)
self.scrollbar = tk.Scrollbar(self.canvas, orient=tk.VERTICAL, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.frame_for_content.pack()
self.canvas.pack(side=tk.LEFT)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
for i in range(100):
tk.Label(self.frame_for_content, text="Hello World - " + str(i)).pack()
self.update()
self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
TestGUI().mainloop()
You don't want self.frame_for_content.pack() because you're using the canvas like a geometry manager for that widget, so self.canvas.create_window takes the place of .pack or .grid.
To get the sizes right, you can get the width & height from the canvas bounding box.
I think this does what you want:
import tkinter as tk
class TestGUI(tk.Tk):
def __init__(self):
super().__init__()
self.canvas = tk.Canvas(self)
self.frame_for_content = tk.Frame(self.canvas)
self.canvas_frame = self.canvas.create_window((0,0), window=self.frame_for_content, anchor=tk.NW)
self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL, command=self.canvas.yview)
self.canvas.pack(side=tk.LEFT)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
for i in range(100):
tk.Label(self.frame_for_content, text="Hello World - " + str(i)).pack()
self.update()
bbox = self.canvas.bbox(tk.ALL)
self.canvas.config(yscrollcommand=self.scrollbar.set,
width=bbox[2], height=bbox[3], scrollregion=bbox)
TestGUI().mainloop()

Is there a way to gray out (disable) a tkinter Frame?

I want to create a GUI in tkinter with two Frames, and have the bottom Frame grayed out until some event happens.
Below is some example code:
from tkinter import *
from tkinter import ttk
def enable():
frame2.state(statespec='enabled') #Causes error
root = Tk()
#Creates top frame
frame1 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame1.grid(column=0, row=0, padx=10, pady=10)
button2 = ttk.Button(frame1, text="This enables bottom frame", command=enable)
button2.pack()
#Creates bottom frame
frame2 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame2.grid(column=0, row=1, padx=10, pady=10)
frame2.state(statespec='disabled') #Causes error
entry = ttk.Entry(frame2)
entry.pack()
button2 = ttk.Button(frame2, text="button")
button2.pack()
root.mainloop()
Is this possible without having to individually gray out all of the frame2's widgets?
I'm using Tkinter 8.5 and Python 3.3.
Not sure how elegant it is, but I found a solution by adding
for child in frame2.winfo_children():
child.configure(state='disable')
which loops through and disables each of frame2's children, and by changing enable() to essentially reverse this with
def enable(childList):
for child in childList:
child.configure(state='enable')
Furthermore, I removed frame2.state(statespec='disabled') as this doesn't do what I need and throws an error besides.
Here's the complete code:
from tkinter import *
from tkinter import ttk
def enable(childList):
for child in childList:
child.configure(state='enable')
root = Tk()
#Creates top frame
frame1 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame1.grid(column=0, row=0, padx=10, pady=10)
button2 = ttk.Button(frame1, text="This enables bottom frame",
command=lambda: enable(frame2.winfo_children()))
button2.pack()
#Creates bottom frame
frame2 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame2.grid(column=0, row=1, padx=10, pady=10)
entry = ttk.Entry(frame2)
entry.pack()
button2 = ttk.Button(frame2, text="button")
button2.pack()
for child in frame2.winfo_children():
child.configure(state='disable')
root.mainloop()
Based on #big Sharpie solution here are 2 generic functions that can disable and enable back a hierarchy of widget (frames "included"). Frame do not support the state setter.
def disableChildren(parent):
for child in parent.winfo_children():
wtype = child.winfo_class()
if wtype not in ('Frame','Labelframe','TFrame','TLabelframe'):
child.configure(state='disable')
else:
disableChildren(child)
def enableChildren(parent):
for child in parent.winfo_children():
wtype = child.winfo_class()
print (wtype)
if wtype not in ('Frame','Labelframe','TFrame','TLabelframe'):
child.configure(state='normal')
else:
enableChildren(child)
I think you can simply hide the whole frame at once.
If used grid
frame2.grid_forget()
If used pack
frame2.pack_forget()
In your case the function would be
def disable():
frame2.pack_forget()
To enable again
def enable():
frame2.pack()
grid_forget() or pack_forget() can be used for almost all tkinter widgets
this is a simple way and reduces the length of your code, I'm sure it works

Categories

Resources