Column span not working properly in Tkinter - python-3.x

I'm a python beginner and as the part of my course I am supposed to code a password generator. But I am facing some issues regarding columnspan.
Here is the code:
from tkinter import *
window = Tk()
window.title("Password Generator...")
window.config(padx=50, pady=50)
logo_path = "logo.png"
image_holder = Canvas(width=200, height=200)
logo_image = PhotoImage(file=logo_path)
image_holder.create_image(100, 100, image=logo_image)
image_holder.grid(column=1, row=0)
# labels
website = Label(text="Website :")
website.grid(row=1, column=0)
email = Label(text="Email/username :")
email.grid(row=2, column=0)
password = Label(text="Password :")
password.grid(row=3, column=0)
# entry
website_entry = Entry(width=45)
website_entry.grid(row=1, column=1,columnspan=2)
email_entry = Entry(width=45)
email_entry.grid(row=2, column=1,columnspan=2)
password_entry = Entry(width=21)
password_entry.grid(row=3,column=1,sticky="ew")
#buttons
genrate_password = Button(text="Generate Password")
genrate_password.grid(row=3, column=2,sticky="ew")
add_button = Button(text="Add",width=40)
add_button.grid(row=4, column=1,columnspan=2)
window.mainloop()
and here is how it is supposed to look like :
here is my result :
How can I move the entry next to password label a little bit right so that it can match the positioning of above two entries.
Thank You...

You can add sticky="ew" to all the entry boxes and buttons to get the desired output. Also I would suggest to put the logo at column 0 with columnspan=3, so it does put it at the center.
from tkinter import *
window = Tk()
window.title("Password Generator...")
window.config(padx=50, pady=50)
logo_path = "images/mypass.png"
image_holder = Canvas(width=200, height=200)
logo_image = PhotoImage(file=logo_path)
image_holder.create_image(100, 100, image=logo_image)
# put at column 0 with columnspan=3 instead
image_holder.grid(column=0, row=0, columnspan=3)
# labels
website = Label(text="Website :")
website.grid(row=1, column=0)
email = Label(text="Email/username :")
email.grid(row=2, column=0)
password = Label(text="Password :")
password.grid(row=3, column=0)
# entry
website_entry = Entry(width=45)
website_entry.grid(row=1, column=1,columnspan=2,sticky="ew") # added sticky
email_entry = Entry(width=45)
email_entry.grid(row=2, column=1,columnspan=2,sticky="ew") # added sticky
password_entry = Entry(width=21)
password_entry.grid(row=3,column=1,sticky="ew") # added sticky
#buttons
genrate_password = Button(text="Generate Password")
genrate_password.grid(row=3, column=2,sticky="ew") # added sticky
add_button = Button(text="Add",width=40)
add_button.grid(row=4, column=1,columnspan=2,sticky="ew") # added sticky
window.mainloop()
Result:
If you want some paddings between those widgets, you can add padx and pady options as well:
from tkinter import *
window = Tk()
window.title("Password Generator...")
window.config(padx=50, pady=50)
logo_path = "images/mypass.png"
image_holder = Canvas(width=200, height=200)
logo_image = PhotoImage(file=logo_path)
image_holder.create_image(100, 100, image=logo_image)
image_holder.grid(column=0, row=0, columnspan=3)
# labels
website = Label(text="Website :")
website.grid(row=1, column=0)
email = Label(text="Email/username :")
email.grid(row=2, column=0)
password = Label(text="Password :")
password.grid(row=3, column=0)
# entry
website_entry = Entry(width=45)
website_entry.grid(row=1, column=1,columnspan=2,sticky="ew",padx=5,pady=3) # added padx and pady
email_entry = Entry(width=45)
email_entry.grid(row=2, column=1,columnspan=2,sticky="ew",padx=5,pady=3) # added padx and pady
password_entry = Entry(width=21)
password_entry.grid(row=3,column=1,sticky="ew",padx=5,pady=3) # added padx and pady
#buttons
genrate_password = Button(text="Generate Password")
genrate_password.grid(row=3, column=2,sticky="ew",padx=5,pady=3) # added padx and pady
add_button = Button(text="Add",width=40)
add_button.grid(row=4, column=1,columnspan=2,sticky="ew",padx=5,pady=3) # added padx and pady
window.mainloop()
Result:

Related

All other widgets are affected when one of the widgets move in a GUI (using the tkinter library in python 3)

Whenever I try to move individual widgets or click a button that produces words effectively moving other widgets that had nothing to do those both specified actions above.
Here is my code:
import tkinter as tk
# Create the main window
window = tk.Tk()
window.title("Price Calculator")
window.geometry("800x600")
window.config(background = "#777474")
def calculate_price():
global input_field
input_field_value = input_field.get()
try:
input = int(input_field_value)
price = input* 0.1
answer.config(text = (f"Your price is ","%.3f"%price,"KWD"))
except ValueError as ve:
answer.config(text = 'What you have just entered are not numbers whatsoever, try again!', fg = "#CD5F66")
price_input = tk.Label(window, text = "Total Pages:", font = "Arial", bg = "#777474", fg = "#FEFCF2")
price_input.grid(column = 0, row = 0)
input_field = tk.Entry(window, font = "Arial", bg = "#FEFCF2")
input_field.grid(column = 1, row = 0, padx = 0,pady = 10)
answer = tk.Label(window, bg = "#777474")
answer.grid(pady = 20)
button_return = tk.Button(window, text = "Calculate Price", command = calculate_price).grid()
# Run the main loop
window.mainloop()
This is my GUI before I click on the button which is called "Calculate Price":
This is my GUI after I have clicked on the button:
The problem here is that I don't want the Total Pages and the entry field to move away from each other whenever I click on the button.
I would suggest to put price_input and input_field into a frame for easier layout management. I also use sticky="w" on the frame, answer and button_return so that they are aligned at the left.
Below is the modified code:
import tkinter as tk
FGCOLOR = "#FEFCF2"
BGCOLOR = "#777474"
ERRCOLOR = "#FF5F66"
# Create the main window
window = tk.Tk()
window.title("Price Calculator")
window.geometry("800x600")
window.config(background="#777474")
def calculate_price():
input_field_value = input_field.get()
try:
input = int(input_field_value)
price = input * 0.1
answer.config(text=f"Your price is {price:.3f} KWD", fg=FGCOLOR)
except ValueError as ve:
answer.config(text='What you have just entered are not numbers whatsoever, try again!', fg=ERRCOLOR)
# create a frame for price_input and input_field
frame = tk.Frame(window, bg=BGCOLOR)
frame.grid(column=0, row=0, padx=10, pady=10, sticky="w")
price_input = tk.Label(frame, text="Total Pages:", font="Arial", bg=BGCOLOR, fg=FGCOLOR)
price_input.grid(column=0, row=0)
input_field = tk.Entry(frame, font="Arial", bg=FGCOLOR)
input_field.grid(column=1, row=0)
answer = tk.Label(window, bg=BGCOLOR)
answer.grid(column=0, row=1, padx=10, pady=10, sticky="w")
button_return = tk.Button(window, text="Calculate Price", command=calculate_price)
button_return.grid(column=0, row=2, sticky="w", padx=10, pady=10)
# Run the main loop
window.mainloop()

how to delete a specific item in the list after a button is clicked in tkinter python

Below is a small code where if you click add button a pop-up will appear where you write desired number. The number in the bottom represents the sum of all numbers you entered.
What I am trying to achieve is to update the sum_lbl and index_no as I delete any of the labels.
Code:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = []
index_no = 0
def destroy(widget):
widget.destroy()
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
while True:
def ok_():
global index_no
name = add_room_area_var.get()
index_no += 1
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=index_no)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:destroy(entry_frame))
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
area_lst.append(int(name))
add_room_area.destroy()
area_sum = sum(area_lst)
sum_lbl.config(text=area_sum)
break
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()
Output:
After deleting the 3rd and 4th label the output is:
I would suggest to change area_lst to dictionary using the frame as the key and the two labels as the value for each row.
Then update destroy() to use area_lst to update the total and indexes:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = {} # dictionary to hold labels of each row using frame as the key
def destroy(frame):
frame.destroy()
del area_lst[frame]
update_total()
# update index of remaining rows
for idx, (lbl, _) in enumerate(area_lst.values(), 1):
lbl['text'] = idx
# function to update the total label
def update_total():
area_sum = sum(int(room['text']) for _, room in area_lst.values())
sum_lbl.config(text=area_sum)
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
def ok_():
name = add_room_area_var.get()
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=len(area_lst)+1)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:destroy(entry_frame))
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
# store current row to area_lst
area_lst[entry_frame] = (index_lbl, add_room_lbl)
add_room_area.destroy()
update_total()
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()
You can allow buttons to call multiple commands, so for your 'close_button' button, I added two more commands: remove the name from 'area_lst' and update the 'sum_lbl' text with the new sum for 'area_lst'
Like this:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = []
index_no = 0
def destroy(widget):
widget.destroy()
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
while True:
def ok_():
global index_no
name = add_room_area_var.get()
index_no += 1
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=index_no)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:[destroy(entry_frame), area_lst.remove(int(name)), sum_lbl.config(text=sum(area_lst))])
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
area_lst.append(int(name))
add_room_area.destroy()
area_sum = sum(area_lst)
sum_lbl.config(text=area_sum)
break
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()

How to get Get value of check button in python tkinter library?

I've created a travel form in which a user will submit name, city, gender, phone number etc. Also, I've created a check button so that a user wants a meal he can tick on the check button.
My Question is How to get values of the Check button if the user has ticked the meal query written in the code.
Can anyone explain to me the logic on how to get the value of the Check button if the user has ticked on it?
from tkinter import *
root = Tk()
root.geometry('800x800')
def b():
print('Name is', namevalue.get()),
print('Phone number is', phonevalue.get())
print('Gender is', gendervalue.get()),
print('Extra Phone number is', phone1value.get()),
print('City is', cityvalue.get())
print('Food is required', )
f1 = Frame(root, bg = 'red', borderwidth = 8, relief = SUNKEN)
f1.grid()
Label(f1, text = 'Welcome to travel agency', pady = 5).grid(row = 0, column = 3)
#Making Widgets or we may call headers
name = Label(root, text = 'name')
phone = Label(root, text = 'Phone')
gender = Label(root, text = 'Enter your gender')
phone1 = Label(root, text = 'Extra Number')
city = Label(root, text = 'Your City')
name.grid(row = 1,column = 0)
phone.grid(row = 2,column = 0)
gender.grid(row = 3, column = 0)
phone1.grid(row = 4, column = 0)
city.grid(row = 5, column = 0)
#Assigining the headers a variable type
namevalue = StringVar()
phonevalue = StringVar()
gendervalue = StringVar()
phone1value = StringVar()
cityvalue = StringVar()
foodservicevalue = IntVar()
nameentry = Entry(root, textvariable = namevalue)
phoneentry = Entry(root, textvariable = phonevalue)
genderentry = Entry(root, textvariable = gendervalue)
cityentry = Entry(root, textvariable = cityvalue)
phone1entry = Entry(root, textvariable = phone1value)
nameentry.grid(row = 1, column = 3)
phoneentry.grid(row = 2, column = 3)
genderentry.grid(row = 3, column = 3)
phone1entry.grid(row = 4, column = 3)
cityentry.grid(row = 5, column = 3)
#Creating Check Button checkbutton
foodservicevalue = Checkbutton(text ='Do you wan\'t any meals', variable = foodservicevalue)
foodservicevalue.grid(row = 6, column = 3, padx = 1)
#Button and packing with assiginn
Button(text = 'Submit', command = b).grid(row = 7, column = 3)
root.mainloop()
This code works:
from tkinter import *
root = Tk()
root.geometry('800x800')
def b():
print('Name is', namevalue.get()),
print('Phone number is', phonevalue.get())
print('Gender is', gendervalue.get()),
print('Extra Phone number is', phone1value.get()),
print('City is', cityvalue.get())
if food_required.get() == 1:
print("Food is required.")
elif food_required.get() == 0:
print("Food is not required.")
# When the check button is clicked, then the value is 1 and it can be get using the .get() function.
# Similarly when the check button is not clicked then the value is 0.
f1 = Frame(root, bg='red', borderwidth=8, relief=SUNKEN)
f1.grid()
Label(f1, text='Welcome to travel agency', pady=5).grid(row=0, column=3)
# Making Widgets or we may call headers
name = Label(root, text='name')
phone = Label(root, text='Phone')
gender = Label(root, text='Enter your gender')
phone1 = Label(root, text='Extra Number')
city = Label(root, text='Your City')
name.grid(row=1, column=0)
phone.grid(row=2, column=0)
gender.grid(row=3, column=0)
phone1.grid(row=4, column=0)
city.grid(row=5, column=0)
# Assigining the headers a variable type
namevalue = StringVar()
phonevalue = StringVar()
gendervalue = StringVar()
phone1value = StringVar()
cityvalue = StringVar()
food_required = IntVar()
nameentry = Entry(root, textvariable=namevalue)
phoneentry = Entry(root, textvariable=phonevalue)
genderentry = Entry(root, textvariable=gendervalue)
cityentry = Entry(root, textvariable=cityvalue)
phone1entry = Entry(root, textvariable=phone1value)
nameentry.grid(row=1, column=3)
phoneentry.grid(row=2, column=3)
genderentry.grid(row=3, column=3)
phone1entry.grid(row=4, column=3)
cityentry.grid(row=5, column=3)
# Creating Check Button #cHECKBUTTON
foodservicevalue = Checkbutton(text='Do you wan\'t any meals', variable=food_required)
foodservicevalue.grid(row=6, column=3, padx=1)
# Button and packing with assiginn
Button(text='Submit', command=b).grid(row=7, column=3)
root.mainloop()
When I saw your code, I found that you have used the variable foodservicevalue as an IntVar() and Checkbutton. I have used the if else statements to fix your issue.
This is #AmeyVijeesh's code but I removed the StringVars:
from tkinter import *
def b():
print("Name is", nameentry.get()),
print("Phone number is", phoneentry.get())
print("Gender is", genderentry.get()),
print("Extra Phone number is", phone1entry.get()),
print("City is", cityentry.get())
if food_required.get() == 1:
print("Food is required.")
elif food_required.get() == 0:
print("Food is not required.")
root = Tk()
root.geometry("800x800")
f1 = Frame(root, bg="red", borderwidth=8, relief="sunken")
f1.grid()
label = Label(f1, text="Welcome to travel agency", pady=5)
label.grid(row=0, column=3)
# Making Widgets or we may call headers
name = Label(root, text="Name")
phone = Label(root, text="Phone")
gender = Label(root, text="Enter your gender")
phone1 = Label(root, text="Extra Number")
city = Label(root, text="Your City")
name.grid(row=1, column=0)
phone.grid(row=2, column=0)
gender.grid(row=3, column=0)
phone1.grid(row=4, column=0)
city.grid(row=5, column=0)
# Assigining the headers a variable type
food_required = IntVar()
nameentry = Entry(root)
phoneentry = Entry(root)
genderentry = Entry(root)
cityentry = Entry(root)
phone1entry = Entry(root)
nameentry.grid(row=1, column=3)
phoneentry.grid(row=2, column=3)
genderentry.grid(row=3, column=3)
phone1entry.grid(row=4, column=3)
cityentry.grid(row=5, column=3)
# Creating Check Button #cHECKBUTTON
foodservicevalue = Checkbutton(text="Do you want any meals", variable=food_required)
foodservicevalue.grid(row=6, column=3, padx=1)
# Button and packing with assiginn
button = Button(text="Submit", command=b)
button.grid(row=7, column=3)
root.mainloop()
Using <tkinter.Entry>.get() is much simpler than creating StringVars and assigning them to the <tkinter.Entry>s

Scrollbar for Dynamically Created Widgets - Python Tkinter [duplicate]

This question already has answers here:
Adding a scrollbar to a group of widgets in Tkinter
(3 answers)
Closed 3 years ago.
I have a GUI that dynamically generates widgets based on the user selected number of systems:
GUI
These widgets are generated using a Callback function like the below sample of code:
class Window():
def __init__(self, master):
master.title('Production Analysis Tool')
# callback function to create entry boxes based on number of systems
self.L0 = Label(root, text="Equipment Parameters:", font = ('TKDefaultFont', 9, 'bold'))
self.L0.grid(row=3,column=0, sticky=W)
inverter_file = r'F:\CORP\PROJECTS\07599-A_Solar Development\Screening\_Production Analysis Tool\User Inputs\Inverter_Data.csv'
module_file = r'F:\CORP\PROJECTS\07599-A_Solar Development\Screening\_Production Analysis Tool\User Inputs\Module_Data.csv'
def update_scroll_region(event):
canvas.configure(scrollregion=canvas.bbox("all"))
def callback(*args):
dynamic_widgets = Frame(canvas)
canvas.create_window(0,0, anchor='nw', window = dynamic_widgets)
self.system_size = int(self.system_size_raw.get())
# Inverter Type
self.Lblank = Label(dynamic_widgets, text = "").grid(row=8, column=1, sticky=W)
self.L3 = Label(dynamic_widgets, text = "Inverter Type")
self.L3.grid(row=9, column=1, sticky=W)
global inverter_types # declare array as global parameter so it can be accessed outside function
inverter_types = []
for i in range(self.system_size):
inverter_list = get_inverter_list(inverter_file)
inverter_list = ["Select"] + inverter_list
self.inverter_types_raw = StringVar()
self.L3a = Label(dynamic_widgets, text = "System {}".format(i+1), font = ('Calibri', 10,'italic'))
self.L3a.grid(row=10+i, column=1, sticky=E)
self.widget = OptionMenu(dynamic_widgets, self.inverter_types_raw, *inverter_list, command = get_values_0)
self.widget.grid(row=10+i, column=2,sticky=EW)
inverter_types.append(self.widget)
dynamic_widgets.bind("<Configure>", update_scroll_region)
global inv_type
inv_type = []
def get_values_0(value):
inv_type.append(value)
button = tk.Button(root, text = "Store Values", font=('Calibri', 10,'italic'), bg = "SlateGray3",command = lambda:[gget_values_0()])
button.grid(row = 61, column = 2, columnspan=8, sticky = 'nesw')
# System Type
self.L1 = Label(root, text = "System Type")
self.L1.grid(row=4, column=1, sticky=W)
self.sys_type_raw = StringVar(root)
types = ['Select', 'Central Inverter', 'String Inverters']
self.popupMenu6 = OptionMenu(root, self.sys_type_raw, *types)
self.popupMenu6.grid(row=4, column=2, sticky=EW)
# Number of Systems
self.L2 = Label(root, text = "Number of Systems")
self.L2.grid(row=6, column=1, sticky=W)
self.system_size_raw = IntVar(root)
choices = list(range(1,50))
self.popupMenu2 = OptionMenu(root, self.system_size_raw, *choices)
self.popupMenu2.grid(row=6, column=2, sticky=EW)
self.system_size_raw.trace("w", callback)
vsb = Scrollbar(root, orient="vertical")
vsb.grid(row=8, column=6, sticky = 'ns')
canvas = Canvas(root, width = 600, height = 200)
vsb.config(command = canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
canvas.grid(row=8,column=0)
# SITE ORIENTATION
self.L12 = Label(root, text="Site Orientation:", font = ('TKDefaultFont', 9, 'bold'))
self.L12.grid(row=66, column=0, sticky=W)
self.L13 = Label(root, text = "Module Tilt Angle (degrees)")
self.L13.grid(row=67, column=1, sticky=W)
self.modtilt_raw = Entry(master)
self.modtilt_raw.grid(row=67, column=2, sticky=EW)
self.L14 = Label(root, text = "Array Azimuth (degrees)")
self.L14.grid(row=68, column=1, sticky=W)
self.arraytilt_raw = Entry(master)
self.arraytilt_raw.grid(row=68, column=2, sticky=EW)
# SUBMIT INFORMATION
self.L27 = Label(root, text=" ").grid(row=84,column=1) # Add row of space
self.cbutton = tk.Button(root, text="SUBMIT",command = self.store_user_inputs, bg = "SlateGray3")
self.cbutton.grid(row=85, column = 0, columnspan=8, sticky = 'ew')
# STORE USER INPUT
def store_user_inputs(self):
self.system_size = np.float(self.system_size_raw.get())
# save all inputs as global parameters so they can be accessed as variables outside of GUI
global params
params = [self.system_type]
root = Tk()
root.configure()
window = Window(root)
root.mainloop()
I would like to place the dynamically generated widgets (Inverter Type, Modules per String, Strings per Inverter, Inverters per System, Module Type, and Max Current per System) into a scrollable frame.
I can post more code if needed.
A scrollable frame can be created by creating a Frame widget on a Canvas. An example is as follows:
vsb = Scrollbar(root, orient = VERTICAL)
vsb.pack(fill=Y, side = RIGHT, expand = FALSE)
canvas = Canvas(root, yscrollcommand=vsb.set)
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vsb.config(command = canvas.yview)
canvas.config(scrollregion = canvas.bbox("all"))
InverterType = Frame(canvas)
canvas.create_window(0, 0, anchor = NW, window = InverterType)
Now make sure to add all the widgets created in the callback function to this InverterType frame.
(TIP - replace root with InverterType)

Tkinter background color issue at scrollbar

I am working on a tkinter script which has a vertical and horizontal scrollbar.
A portion of the window below the vertical scrollbar is not picking up the background color I'm applying.
I have tried the following color options still the small portion is not picking up.
Image:
Sample window snapshot
Full Code:
from tkinter.tix import *
from tkinter import *
import collections
root = Tk()
root.configure(background='steel blue')
# Global variables
fname = ''
# Variables for setting the height and width of widget
# Variables to set Height
actualRootHeight = 300
rootHScale = 25
rootHOffset = 100
canvasHeight = 300
root2CanvasHMargin =65
# Variables to set Width
rootWScale = 10
rootWOffset = 200
canvasWidth = 300
root2CanvasWMargin = 20
inpWidth = 0
# Lists to save configs
inpParamList = collections.OrderedDict()
paramListRef = collections.OrderedDict()
updatedParamList = collections.OrderedDict()
entryList = []
labels = []
# All widget coding is done here
class guiList(Frame):
global root
# Constructor - Use as a control structure
def __init__(self,parent):
Frame.__init__(self,parent)
self.parent = parent
self.readParams()
self.setGeometry()
self.initUI()
self.controlUI()
def onFrameConfigure(self, event, Canvas1):
# Reset the scroll region to encompass the inner frame
Canvas1.configure(scrollregion=Canvas1.bbox("all"), background='steel blue')
# All widget edition is done here
def initUI(self):
global paramListRef
titleStr = sys.argv[1]
self.parent.title(titleStr)
self.grid(row=0, column=0)
inpConfigs = inpParamList.items()
# Add a canvas and call Frame as it's child widget
# Scrollbar can be added to Canvas
Canvas1 = Canvas(self, width=canvasWidth, height=canvasHeight, borderwidth=0, bg="light steel blue")
vsb = Scrollbar(self, orient="vertical", command=Canvas1.yview, bg="light steel blue", troughcolor="steel blue", highlightcolor="light steel blue", activebackground="light steel blue", highlightbackground="light steel blue")
Canvas1.configure(yscrollcommand=vsb.set)
vsb.grid(column=2, sticky='NS')
hsb = Scrollbar(self, orient="horizontal", command=Canvas1.xview, bg="light steel blue", troughcolor="steel blue")
Canvas1.configure(xscrollcommand=hsb.set)
hsb.grid(column=0, sticky='EW')
Canvas1.grid(row=0, column=0, sticky='NWES')
# Create new Frame for input configs
Frame1 = Frame(Canvas1, width=canvasWidth, height=canvasHeight, bg="light steel blue")
Canvas1.create_window((1,1),window=Frame1, anchor="nw", tags="Frame1")
Frame1.bind("<Configure>", lambda event, arg=Canvas1: self.onFrameConfigure(event, arg))
# Loop through the input configs
i = 0
# Add label and combobox in loop
for k,v in inpConfigs:
# Label widgets
lbl1 = Label(Frame1, text=k, bg="light steel blue", font=("Helvetica", 12, "bold"), fg="steel blue")
lbl1.grid(row = i, column = 0, padx=10, pady=5, sticky='W')
labels.append(lbl1)
# Combo-box widget for configurations
tkvar = StringVar(Frame1)
tkvar.set(v[0])
entry1 = OptionMenu(Frame1, tkvar, *v)
entry1.configure(width=20, anchor=W, bg="steel blue", fg="white", font=("Helvetica", 11, "bold"))
entry1.grid(row = i, column=1, padx=10, pady=5, sticky='E')
#entry1.grid_columnconfigure(2, weight=2)
paramListRef[k] = tkvar
i += 1
# Read the updated configs after the button click
def readUpdatedParams(self):
global updatedParamList
for k,v in paramListRef.items():
updatedParamList[k] = v.get()
root.destroy()
self.writeBack()
# Seperate Frame for buttons
# Upon clicking read updted params
def controlUI(self):
Frame2 = Frame(self, bg="steel blue")
Frame2.grid(row=2, column = 0, sticky="EW")
b = Button(Frame2, text="OK", command=self.readUpdatedParams, bg="light steel blue", fg="steel blue", font=("Helvetica", 11, "bold"))
#b.grid(row=1, column=1, pady=10)
b.pack(fill="none", expand=True, pady = 10)
# Read the file and create a key, value pair for configs
# Lines in file is split with space as delimiter
# First column is the config name and rest are all possible value
def readParams(self):
global inpParamList
global inpWidth
f = open(fname)
for line in f:
val = {}
val = line.split()
key = val.pop(0)
# Get the max width of key to adjust widget width
inpWidth = len(key) if (len(key) > inpWidth) else inpWidth
inpParamList[key] = val
# Geometry ( X-width x Y-width + X-position + Y-position)
# Based on the number of elements in the config list
# the height of the widget is set (Max is 75% of screen size)
def setGeometry(self):
global actualRootHeight
global canvasWidth
global canvasHeight
listLen = len(inpParamList)
rootWinwidth = int(inpWidth *rootWScale) + rootWOffset
rootWinheight = (listLen * rootHScale ) + rootHOffset
screenWidth = self.winfo_screenwidth()
screenHeight = int(self.winfo_screenheight() * 0.75)
if rootWinheight < screenHeight :
actualRootHeight = rootWinheight
else :
actualRootHeight = screenHeight
canvasWidth = rootWinwidth - root2CanvasWMargin
canvasHeight = actualRootHeight - root2CanvasHMargin
rootWinresolution = str(rootWinwidth)+'x'+str(actualRootHeight)+'+'+'0'+'+'+'0'
root.geometry(rootWinresolution)
# Sub routine to write back the config file.
def writeBack(self):
fr = open("bt_top.param.config",'w')
for k,v in updatedParamList.items():
print(k,v)
fr.write(k)
fr.write(" ")
fr.write(v)
fr.write("\n")
fr.close()
# Main Function
# Define Window geometry and other top level stuff here
# Do not go into widget coding here
def main():
global fname
# Get File name from command line argument
fname = sys.argv[2]
app = guiList(root)
root.mainloop()
# The __name__ variable decides what to run
# Below lines make this file run stand-alone
if __name__ == '__main__':
Any suggestions are welcome. Thanks
-Vinay
The piece of black is the background of self, your guiList class. Add a line self.config(bg="steel blue") to its __init__() function (or to initUI() I suppose) to fix it.

Resources