I cannot get the state of a (tk.)Label and (tk.)Checkbutton to visually turn to disable and normal depending on the value of an OptionMenu.
The command binding on the OptionMenu below seems fine, but my use of configure(state=...), in updateState() has no visible effect. Should I force some "refresh" or "repaint" (if yes how in the partial code below?) or am I missing something else?
import Tkinter
from Tkinter import Frame, LabelFrame, Label, Entry, Button, StringVar, OptionMenu, Checkbutton, IntVar, DISABLED, NORMAL
class GeneratorDialog:
# The UI to configure the settings by the user
def __init__(self, root, ctrl):
self.__root = root
self.__ctrl = ctrl
def updateState(self, value, label, entry):
if(value.get()==CONST.FORMAT_PDF): # test works, as the dialog below show in alternance as expected
tkMessageBox.showinfo('Info', message="enabling checkbox")
label.configure(state=NORMAL)
entry.configure(state=NORMAL)
else:
tkMessageBox.showinfo('Info', message="disabling the checkbox")
label.configure(state=DISABLED)
entry.configure(state=DISABLED)
#self.__root.update_idletasks() # how to force "redraw" with grid() manager?
def show(self):
self.__root.title(CONST.APP_NAME)
mainFrame = Frame(self.__root)
mainFrame.grid(sticky='ew')
outputFrame = LabelFrame(mainFrame, text='Output Settings')
outputFrame.grid(column=0, row=1, padx=5, pady=5, sticky='ew')
keepGeneratedScribusFilesLabel = Label(outputFrame, text='Keep Scribus Files:', width=15, anchor='e')
keepGeneratedScribusFilesLabel.grid(column=4, row=2, padx=5, pady=5, sticky='e')
keepGeneratedScribusFilesCheckbox = Checkbutton(outputFrame, variable=self.__ctrl.getKeepGeneratedScribusFilesCheckboxVariable(), anchor='w')
keepGeneratedScribusFilesCheckbox.grid(column=5, row=2, padx=5, pady=5, sticky='w')
mergeOutputLabel = Label(outputFrame, text='Merge in Single File:', width=15, anchor='w')
mergeOutputLabel.grid(column=0, row=2, padx=5, pady=5, sticky='w')
mergeOutputCheckbox = Checkbutton(outputFrame, variable=self.__ctrl.getMergeOutputCheckboxVariable())
mergeOutputCheckbox.grid(column=1, row=2, padx=5, pady=5, sticky='w')
outputFormatLabel = Label(outputFrame, text='Output Format:', anchor='e')
outputFormatLabel.grid(column=2, row=2, padx=5, pady=5, sticky='e')
outputFormatListBox = OptionMenu(outputFrame, self.__ctrl.getSelectedOutputFormat(), *self.__ctrl.getOutputFormatList(),
command=lambda l=keepGeneratedScribusFilesLabel, c=keepGeneratedScribusFilesCheckbox, v=self.__ctrl.getSelectedOutputFormat(): self.updateState(v, l, c))
outputFormatListBox.grid(column=3, row=2, padx=5, pady=5, sticky='w')
# Buttons to Cancel or to Run the Generator with the given Settings
helpButton = Button(buttonFrame, text='Help', width=10, command=self.__ctrl.helpButtonHandler)
helpButton.grid(column=0, row=0, padx=5, pady=5, sticky='e')
cancelButton = Button(buttonFrame, text='Cancel', width=10, command=self.__ctrl.buttonCancelHandler)
cancelButton.grid(column=1, row=0, padx=5, pady=5, sticky='e')
generateButton = Button(buttonFrame, text='Generate', width=10, command=self.__ctrl.buttonOkHandler)
generateButton.grid(column=2, row=0, padx=5, pady=5, sticky='e')
# Finally show the Generator Dialog
mainFrame.grid()
self.__root.grid()
self.__root.mainloop()
full code is at https://github.com/berteh/ScribusGenerator/blob/93a12de4be28054344533ad8fc424e37180668de/ScribusGenerator.py#L278
solved it by using class variables (self.X) instead of lambda local variables.
still don't know why the former code (with local variables in the lambda) would not update the status of the Tk elements (maybe it created copies thereof?)... but I found a workaround.
thanks all for your help
Related
from tkinter import *
win=Tk()
var = StringVar()
l = Label(win, bg='white', width=15)
l.grid(row=17,column=1,padx=10, pady=10, sticky='w')
def print1_selection():
if var.get()=="Number":
lab1= Label(win, text="Enter a number").grid(row=4, column=0)
ent1=Entry(win).grid(row=4, column=1)
l.config(text='you have selected ' + var.get())
elif var.get()=="Alphabet":
lab21= Label(win, text="Enter an alphabet").grid(row=5, column=0)
ent21=Entry(win).grid(row=5, column=1)
l.config(text='you have selected ' + var.get())
lbl4=Label(win, text="Select One", bg="crimson", fg="white", font=("times new
roman",15,"bold")).grid(row=1, column=0, padx=10, pady=10, sticky='w')
r1 = Radiobutton(win, text='Number',variable=var, value='Number', command=print1_selection, width=22)
r1.grid(row=2,column=0,padx=10, pady=10)
r2 = Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22)
r2.grid(row=2,column=1,padx=10, pady=10)
win.mainloop()
In this code I want that when I select radiobutton number, only enter a number should appear and same for the other.
But the problem is that when I select number after selecting alphabet, it shows both. I need only the selected one and eliminate the other instantly.
This is how I would approach this issue:
from tkinter import Tk, StringVar, Label, Frame, Entry, Radiobutton
def print1_selection():
for widget in entry_frame.winfo_children():
widget.destroy()
value = var.get()
lbl.config(text='You have selected ' + value)
if value == "Number":
Label(entry_frame, text="Enter a number").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
elif value == "Alphabet":
Label(entry_frame, text="Enter an alphabet").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
win = Tk()
var = StringVar(value=0)
entry_frame = Frame(win)
entry_frame.grid(row=2, column=0, columnspan=2)
lbl = Label(win, bg='white', width=20)
lbl.grid(row=3, column=0, columnspan=2, padx=10, pady=10, sticky='w')
Label(win, text="Select One", bg="crimson", fg="white", font=("times new roman", 15, "bold")).grid(row=0, column=0, padx=10, pady=10, sticky='w')
Radiobutton(win, text='Number', variable=var, value='Number', command=print1_selection, width=22).grid(row=1, column=0, padx=10, pady=10)
Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22).grid(row=1, column=1, padx=10, pady=10)
win.mainloop()
As You can see if You don't plan on using the widgets instance anywhere You don't have to assign it to a variable. Also no need to configure label in both statements since that will be done anyways so just do it at the beginning, also rows start from 0 too. Frames help with organizing widgets. Also if You want neither of the radiobuttons selected set the variable to 0.
I have a simple label and entry field that would:
1) Create a static label and clear the entry field after confirmation button click
2) Clear static label after reset button click
Is there any way to overwrite the entry field with a static label of the user input on the confirmation click instead of creating a new static label? And overwriting the static label with an empty entry field on the reset click?
Thank you for the help in advance.
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.pack()
def reset():
set_cname.destroy()
cbtn['state'] = NORMAL
def confirm():
global set_cname
text1="Customer Name: " + entry1.get()
set_cname = Label(frame1, text=text1)
set_cname.grid(row=3, column=0, columnspan=1)
entry1.delete(0, 'end')
cbtn['state'] = DISABLED
cname = Label(frame1, text="Customer Name: ").grid(padx=5, pady=5, columnspan=2, sticky=W)
entry1 = Entry(frame1)
entry1.grid(row=0, column=2, padx=5)
cbtn = Button(frame1, text="Confirm", command=confirm, width=20)
cbtn.grid(row=1, column=4, padx=5, pady=5)
rbtn = Button(frame1, text="Reset Names", command=reset, width=20)
rbtn.grid(row=2, column=4, padx=5, pady=5)
root.mainloop()
You can replace the Entry with a Label by first creating both and then using pack() to switch between them. The trick is to not let their different sizes affect the application layout, which can be accomplished by disabling size propagation.
In my example I create a new frame (entry_frame) with a fixed size and then disable size propagation (.pack_propagate(False)). Then I use this new frame to contain the Entry/Label. Im giving the entry_frame the bg color khaki to let you see exactly where it is.
I fiddled a bit with the column numbers also.
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.pack()
def reset():
text_label.pack_forget()
entry1.pack()
cbtn['state'] = NORMAL
def confirm():
global set_cname
entry1.pack_forget()
text_label.config(text=entry1.get())
text_label.pack(side='left')
entry1.delete(0, 'end')
cbtn['state'] = DISABLED
cname = Label(frame1, text="Customer Name: ")
cname.grid(row=0, column=0, padx=5, pady=5, sticky=W)
entry_frame = Frame(frame1, width=130, height=20, bg='khaki')
entry_frame.grid(row=0, column=1, padx=5, pady=5, sticky='nsew')
entry_frame.pack_propagate(False) # Disable size propagation
entry1 = Entry(entry_frame) # Customer name entry
entry1.pack()
text_label = Label(entry_frame) # Label to hold customer name
cbtn = Button(frame1, text="Confirm", command=confirm, width=20)
cbtn.grid(row=1, column=2, padx=5, pady=5)
rbtn = Button(frame1, text="Reset Names", command=reset, width=20)
rbtn.grid(row=2, column=2, padx=5, pady=5)
root.mainloop()
Be aware that this solution will be sensitive to font size changes.
I'm working on a g.u.i. with tkinter. I'm currently trying to make a couple of labelframes with several checkbuttons. The problem is that one checkbutton gets crossed in a window, and another in the other window get crossed too.
I've been looking for similar questions, but I've found none. Being a beginner, I don't really understand where the problem is.
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from scipy.stats import linregress
import pandas as pd
window= tk.Tk()
#creating the 2 labelframes
models = tk.LabelFrame(window, text="Models", padx=10, pady=10)
models.grid(padx=10, pady=10, sticky='W')
param = tk.LabelFrame(window, text="params", padx=10, pady=10)
param.grid(column=0, row=10, sticky='W', padx= 10)
# adding checkbuttons to the first labelframe
lin_cb = tk.Checkbutton(models, text="linear regression")
lin_cb.grid(column=0, row=2, sticky='W')
nlin_cb = tk.Checkbutton(models, text="non-linear regression")
nlin_cb.grid(column=0, row=5, sticky='W')
#labels for second labelframe
tk.Label(param, text="substate").grid(row=1, sticky='W')
tk.Label(param, text="velocity").grid(row=2, sticky='W')
tk.Label(param, text="if inhibited").grid(row=3, sticky='W')
tk.Label(param, text="inibitor").grid(row=4, sticky='W')
#checkbutton
su_M=tk.Checkbutton(param, text='M')
su_M.grid(column=1, row=1, sticky='W')
su_mM=tk.Checkbutton(param, text='mM')
su_mM.grid(column=2, row=1, sticky='W')
window.mainloop()
Before continuing with the program extracting the information from the crossed checkbutton, I have to understand how to solve this problem. Thanks to everyone. I hope that I gave you all the necessary information. I tried to summarise the code as much as possible.
To use a Checkbutton, you need to create tkinter variables and associate them with each Checkbutton.
import tkinter as tk
window= tk.Tk()
models = tk.LabelFrame(window, text="Models", padx=10, pady=10)
models.grid(padx=10, pady=10, sticky='W')
param = tk.LabelFrame(window, text="params", padx=10, pady=10)
param.grid(column=0, row=10, sticky='W', padx= 10)
all_vars = [tk.IntVar() for _ in range(4)] #create 4 IntVars in one go
for i in all_vars : #set all vars to 0
i.set(0)
lin_cb = tk.Checkbutton(models, text="linear regression",variable=all_vars[0]) #set variable for each checkbutton
lin_cb.grid(column=0, row=2, sticky='W')
nlin_cb = tk.Checkbutton(models, text="non-linear regression",variable=all_vars[1])
nlin_cb.grid(column=0, row=5, sticky='W')
tk.Label(param, text="substate").grid(row=1, sticky='W')
tk.Label(param, text="velocity").grid(row=2, sticky='W')
tk.Label(param, text="if inhibited").grid(row=3, sticky='W')
tk.Label(param, text="inibitor").grid(row=4, sticky='W')
su_M=tk.Checkbutton(param, text='M',variable=all_vars[2])
su_M.grid(column=1, row=1, sticky='W')
su_mM=tk.Checkbutton(param, text='mM',variable=all_vars[3])
su_mM.grid(column=2, row=1, sticky='W')
window.mainloop()
I would like to know why the methods SavePVParms Close and ApplyGraph are not defined when I call them through the buttons. I know that if I put them inside __init__ they will work and my problem is solved but I don't understand why it wouldn't work the way it is. I tried to look for this question and found this Python Class: Global/Local variable name not defined and this Python says global name not defined but forgive me if I can't understand the answer there. Could you help me understand why?
Background: This class is a top level window that popups when I press a button in the root window (here i am just showing you guys the toplevel window directly). It is supposed to pass a dictionary of all the entries when I save it (not yet implemented). **Additionally (but not required to answer if you don't want to) is this an adequate style of coding in OOP? (less than 1 week learning tkinter and moving from precedural python to OOP python).
import Tkinter as tk
import ttk
class PVDialog(tk.Toplevel):
def SavePVParms(self):
print "saved"
self.destroy()
def Close(self):
self.destroy()
def ApplyGraph(self):
print 'applied'
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
print parent
self.title('PV Parameters Configuration')
self.geometry('800x480')
self.resizable(width=False, height=False)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=8)
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=2)
# ====== FRAMES =======
lb1Frame = tk.LabelFrame(self, text='Electric Properties')
lb1Frame.grid(row=0, column=0, sticky='ewns', pady=(15, 2), padx=(30,10))
AdvFrame = tk.LabelFrame(self, text='Thermal Properties')
AdvFrame.grid(row=1, column=0, sticky='ewns', pady=5, padx=(30,10))
pcurveFrame = tk.LabelFrame(self, text='PV Curves')
pcurveFrame.grid(row=0, column=1, sticky='ewns', padx=(0,30), pady=(15,5),rowspan=2)
ctrlFrame = tk.Frame(self)
ctrlFrame.grid(row=2, column=0, columnspan=2, sticky='ens', padx=20, pady=(2, 20))
# ======== PARAMETER INPUT DATA FRAME ============= #
labelName = tk.Label(lb1Frame, text='Name', anchor='w')
labelCellType = tk.Label(lb1Frame, text='Cell Type', anchor='w')
labelPower = tk.Label(lb1Frame, text='Rated Power [W]', anchor='w')
labelOV = tk.Label(lb1Frame, text='Open Voltage [V]', anchor='w')
labelSCC = tk.Label(lb1Frame, text='Short-circuit Current [A]', anchor='w')
labelMPC = tk.Label(lb1Frame, text='Maximum Point Current [I]', anchor='w')
labelMPV = tk.Label(lb1Frame, text="Maximum point Voltage [V]", anchor='w')
labelSeries = tk.Label(lb1Frame, text='Cells in series', anchor='w')
labelPallel = tk.Label(lb1Frame, text='Cells in parallel', anchor='w')
labelNOCT = tk.Label(AdvFrame, text='NOCT', anchor='w')
labelThC = tk.Label(AdvFrame, text='Current T factor [%/K]', anchor='w')
labelThV = tk.Label(AdvFrame, text='Voltage T factor [%/K]', anchor='w')
labelThP = tk.Label(AdvFrame, text='Power T factor [%/K]', anchor='w')
labelName.grid(row=0, sticky='ew', padx=10, pady=2)
labelCellType.grid(row=1, sticky='ew', padx=10, pady=2)
labelPower.grid(row=2, sticky='ew', padx=10, pady=2)
labelOV.grid(row=3, sticky='ew', padx=10, pady=2)
labelSCC.grid(row=4, sticky='ew', padx=10, pady=2)
labelMPC.grid(row=5, sticky='ew', padx=10, pady=2)
labelMPV.grid(row=6, sticky='ew', padx=10, pady=2)
labelSeries.grid(row=7, sticky='ew', padx=10, pady=2)
labelPallel.grid(row=8, sticky='ew', padx=10, pady=2)
labelNOCT.grid(row=9 , sticky='ew', padx=10, pady=2)
labelThC.grid(row=10, sticky='ew', padx=10, pady=2)
labelThV.grid(row=11, sticky='ew', padx=10, pady=2)
labelThP.grid(row=12, sticky='ew', padx=10, pady=2)
entryName = ttk.Entry(lb1Frame, show='Default')
entryCellType = ttk.Combobox(lb1Frame)
entryPower = ttk.Entry(lb1Frame)
entryOV = ttk.Entry(lb1Frame)
entrySCC = ttk.Entry(lb1Frame)
entryMPC = ttk.Entry(lb1Frame)
entryMPV = ttk.Entry(lb1Frame)
entrySeries = ttk.Entry(lb1Frame)
entryPallel = ttk.Entry(lb1Frame)
entryNOCT = ttk.Entry(AdvFrame, width=23)
entryThC = ttk.Entry(AdvFrame, width=23)
entryThV = ttk.Entry(AdvFrame, width=23)
entryThP = ttk.Entry(AdvFrame, width=23)
entryName.grid(row=0, column=1, sticky='ew')
entryCellType.grid(row=1, column=1, sticky='ew')
entryPower.grid(row=2, column=1, sticky='ew')
entryOV.grid(row=3, column=1, sticky='ew')
entrySCC.grid(row=4, column=1, sticky='ew')
entryMPC.grid(row=5, column=1, sticky='ew')
entryMPV.grid(row=6, column=1, sticky='ew')
entrySeries.grid(row=7, column=1, sticky='ew')
entryPallel.grid(row=8, column=1, sticky='ew')
entryNOCT.grid(row=9, column=1, sticky='w', padx=(26,0))
entryThC.grid(row=10, column=1, sticky='w', padx=(26,0))
entryThV.grid(row=11, column=1, sticky='w', padx=(26,0))
entryThP.grid(row=12, column=1, sticky='w', padx=(26,0))
# ==== BUTTON COMANDS ======
saveBttn = ttk.Button(ctrlFrame, text='Save', command=SavePVParms)
closBttn = ttk.Button(ctrlFrame, text='Cancel', command=Close)
applyBttn = ttk.Button(ctrlFrame, text='Apply', command=ApplyGraph)
saveBttn.grid()
closBttn.grid(row=0, column=1, padx=10)
applyBttn.grid(row=0, column=2, padx=(0, 10))
# ======== RUNNIG THE CLIENT ============
root = tk.Tk()
dialog = PVDialog(root)
root.mainloop()
Update: As I was making about to submit this question, I remembered that __init__ is the first thing that is read and executed in the Class, so that's why the are defined if I put them in __init__. I still don't understand why python can't call them if they are outside __init__ doesn't python read the whole class? how can I call then self.method that is outside of __init__ then?. Thanks!
SavePVParms, Close, ApplyGraph methods are belong to your class, so you need to use self. to tell interpreter that, you want to use methods from your class.
saveBttn = ttk.Button(..., command=self.SavePVParms)
For coding standarts, you should check PEP 8 but as long as you are consistent with your style, it shouldn't matter that much.
Building a small application for personal use with Python and thought I'd try my hand with a little GUI programming using Tkinter. This is the GUI I've created so far:
Application doubts:
How can I make sure that the three LableFrames - A, B and C in the screenshot - have the same width? (Or rather, have the width equal to the widest of the three? For example, in the screenshot, A is the widest and I'd like B and C to also be as wide - up to the line D).
(It doesn't have to dynamically calculated - it is enough if I can ensure that the width are the same when I code it, the first time round. They don't need to change on runtime.)
Tk Grid Geometry Manager doubts:
When you use frames, is the grid (row, column) specific to only the size of the frame or is it calculated based on the size of the form (root window)?
How is the size of a column determined in a grid?
I haven't fully understood what 'weight' does within a grid. When should it be used?
The Python GUI Code:
import Tkinter
if __name__ == '__main__':
form = Tkinter.Tk()
getFld = Tkinter.IntVar()
form.wm_title('File Parser')
stepOne = Tkinter.LabelFrame(form, text=" 1. Enter File Details: ")
stepOne.grid(row=0, columnspan=7, sticky='W', \
padx=5, pady=5, ipadx=5, ipady=5)
helpLf = Tkinter.LabelFrame(form, text=" Quick Help ")
helpLf.grid(row=0, column=9, columnspan=2, rowspan=8, \
sticky='NS', padx=5, pady=5)
helpLbl = Tkinter.Label(helpLf, text="Help will come - ask for it.")
helpLbl.grid(row=0)
stepTwo = Tkinter.LabelFrame(form, text=" 2. Enter Table Details: ")
stepTwo.grid(row=2, columnspan=7, sticky='W', \
padx=5, pady=5, ipadx=5, ipady=5)
stepThree = Tkinter.LabelFrame(form, text=" 3. Configure: ")
stepThree.grid(row=3, columnspan=7, sticky='W', \
padx=5, pady=5, ipadx=5, ipady=5)
inFileLbl = Tkinter.Label(stepOne, text="Select the File:")
inFileLbl.grid(row=0, column=0, sticky='E', padx=5, pady=2)
inFileTxt = Tkinter.Entry(stepOne)
inFileTxt.grid(row=0, column=1, columnspan=7, sticky="WE", pady=3)
inFileBtn = Tkinter.Button(stepOne, text="Browse ...")
inFileBtn.grid(row=0, column=8, sticky='W', padx=5, pady=2)
outFileLbl = Tkinter.Label(stepOne, text="Save File to:")
outFileLbl.grid(row=1, column=0, sticky='E', padx=5, pady=2)
outFileTxt = Tkinter.Entry(stepOne)
outFileTxt.grid(row=1, column=1, columnspan=7, sticky="WE", pady=2)
outFileBtn = Tkinter.Button(stepOne, text="Browse ...")
outFileBtn.grid(row=1, column=8, sticky='W', padx=5, pady=2)
inEncLbl = Tkinter.Label(stepOne, text="Input File Encoding:")
inEncLbl.grid(row=2, column=0, sticky='E', padx=5, pady=2)
inEncTxt = Tkinter.Entry(stepOne)
inEncTxt.grid(row=2, column=1, sticky='E', pady=2)
outEncLbl = Tkinter.Label(stepOne, text="Output File Encoding:")
outEncLbl.grid(row=2, column=5, padx=5, pady=2)
outEncTxt = Tkinter.Entry(stepOne)
outEncTxt.grid(row=2, column=7, pady=2)
outTblLbl = Tkinter.Label(stepTwo, \
text="Enter the name of the table to be used in the statements:")
outTblLbl.grid(row=3, column=0, sticky='W', padx=5, pady=2)
outTblTxt = Tkinter.Entry(stepTwo)
outTblTxt.grid(row=3, column=1, columnspan=3, pady=2, sticky='WE')
fldLbl = Tkinter.Label(stepTwo, \
text="Enter the field (column) names of the table:")
fldLbl.grid(row=4, column=0, padx=5, pady=2, sticky='W')
getFldChk = Tkinter.Checkbutton(stepTwo, \
text="Get fields automatically from input file",\
onvalue=1, offvalue=0)
getFldChk.grid(row=4, column=1, columnspan=3, pady=2, sticky='WE')
fldRowTxt = Tkinter.Entry(stepTwo)
fldRowTxt.grid(row=5, columnspan=5, padx=5, pady=2, sticky='WE')
transChk = Tkinter.Checkbutton(stepThree, \
text="Enable Transaction", onvalue=1, offvalue=0)
transChk.grid(row=6, sticky='W', padx=5, pady=2)
transRwLbl = Tkinter.Label(stepThree, \
text=" => Specify number of rows per transaction:")
transRwLbl.grid(row=6, column=2, columnspan=2, \
sticky='W', padx=5, pady=2)
transRwTxt = Tkinter.Entry(stepThree)
transRwTxt.grid(row=6, column=4, sticky='WE')
form.mainloop()
(Note: For Python 2.4.3)
If you use the same columnspan and use sticky='WE' on all three LabelFrames then they should have the same width. For example, you want to use
stepTwo = Tkinter.LabelFrame(form, text=" 2. Enter Table Details: ")
stepTwo.grid(row=2, columnspan=7, sticky='WE', \
padx=5, pady=5, ipadx=5, ipady=5)
Questions
1) When you use frames, is the grid (row, column) specific to only the
size of the frame or is it calculated based on the size of the form
(root window)?
There is an interdependence here. The preferred size of the form will depend on the preferred sizes of the children and the layout, but the actual sizes of the children will depend on the actual size of the form and the layout. Layout is done from the children to the root to determine the preferred sizes, and then when it gets to the root, the preferred size is used as the actual size (unless overridden). Layout then goes back down assigning actual sizes.
2) How is the size of a column determined in a grid?
The preferred size of a column is determined based to be the minimum preferred width of all the items in that row. The actual size of the column is determined by the preferred size plus some percentage of the extra space of the parent widget.
3) I haven't fully understood what 'weight' does within a grid. When
should it be used?
The weight determines the percentage of extra space that I mentioned above. The amount of the extra space given to the column is column_weight/total_weight.