So I'm trying to make this tkinter GUI in which you can add or search for a customer (the customer is stored in a SQlite database). Problem is, I can't see a way of making the def for when the add customer button is pressed, for as far as I know, I would need to use the names of the variables from lower down in the program where the widgets are created. I could switch the order of the functions around, but then the widgets would be calling functions that have not already been created. Can someone help fix this probem? Thanks in advance.
Here's the code:
from tkinter import *
app = Tk()
app.minsize(400,420)
app.title("Gatecode Manager")
app.resizable(False, False)
def add():
first = createWindow().firstAdd.get()
last = createWindow().firstAdd.get()
phone = createWindow().numberAdd.get()
def createWindow():
Label(text="Welcome to Gatecode Manager", font=("bold", 17)).grid(row=0, columnspan=2, pady=30, sticky=N)
Label(text="Search for a Customer").grid(row=1, column=0, padx=30, pady=10)
Label(text="First Name:").grid(row=2, column=0, padx=30, pady=10)
firstSearch = Entry().grid(row=3, column=0, padx=30)
Label(text="Last Name:").grid(row=4, column=0, padx=30, pady=10)
lastSearch = Entry().grid(row=5, column=0, padx=30)
Label(text="Add Customer to System").grid(row=1, column=1, padx=30, pady=10)
Label(text="First Name:").grid(row=2, column=1, padx=30, pady=10)
firstAdd = Entry().grid(row=3, column=1, padx=30)
Label(text="Last Name:").grid(row=4, column=1, padx=30, pady=10)
lastAdd = Entry().grid(row=5, column=1, padx=30)
Label(text="Phone Number:").grid(row=6, column=1, padx=30, pady=10)
numberAdd = Entry().grid(row=7, column=1, padx=30)
add = Button(text="Add", command="null").grid(padx=30, pady=10, column=1)
app.mainloop()
createWindow()
I find it difficult to understand exactly how you want this program to function. Is the add button supposed to call the function add() which then calls createWindow()?
I'm guessing a little here but what about:
1) Don't create the GUI in a function. A function will keep the variables in the scope of the functioin.
2) Use StringVar() to access entries. Since you don't save the identity of your entries it becomes impossible to interrogate them.
Example:
from tkinter import *
app = Tk()
app.minsize(400,420)
app.title("Gatecode Manager")
app.resizable(False, False)
def add():
first = firstAddVar.get()
last = firstAddVar.get()
phone = numberAddVar.get()
Label(text="Welcome to Gatecode Manager", font=("bold", 17)).grid(row=0,
columnspan=2, pady=30, sticky=N)
Label(text="Search for a Customer").grid(row=1, column=0, padx=30, pady=10)
Label(text="First Name:").grid(row=2, column=0, padx=30, pady=10)
firstSearchVar = StringVar()
firstSearch = Entry(textvar=firstSearchVar).grid(row=3, column=0, padx=30)
Label(text="Last Name:").grid(row=4, column=0, padx=30, pady=10)
lastSearchVar = StringVar()
lastSearch = Entry(textvar=lastSearchVar).grid(row=5, column=0, padx=30)
Label(text="Add Customer to System").grid(row=1, column=1, padx=30, pady=10)
Label(text="First Name:").grid(row=2, column=1, padx=30, pady=10)
firstAddVar = StringVar()
firstAdd = Entry(textvariable=firstAddVar).grid(row=3, column=1, padx=30)
Label(text="Last Name:").grid(row=4, column=1, padx=30, pady=10)
lastAddVar = StringVar()
lastAdd = Entry(textvariable=lastAddVar).grid(row=5, column=1, padx=30)
Label(text="Phone Number:").grid(row=6, column=1, padx=30, pady=10)
numberAddVar = StringVar()
numberAdd = Entry(textvariable=numberAddVar).grid(row=7, column=1, padx=30)
add = Button(text="Add", command=add).grid(padx=30, pady=10, column=1)
app.mainloop()
When your GUIs become more complex you should study OOP.
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.
thanks for helping!
I have a spreadsheet that records my income and expenses, with dates, description, debit and credit amount. I wanted to used openpyxl to automate the process of adding values that are in a particular category, the program kind of works now, but the problem is: when I am searching for a phrase that don't exist in the sheet, the program crash, it can not do the things it suppose to before and after the search phrase that dont exist.
for example,
when i wanted to calculate the subtotal of search phrase "wage" and the put the subtotal into a target cell, it works fine. the problem comes out when i ask the program to look for something that isnt there.
I ask the program to look for wage, and create a subtotal, works fine and suppose to store the value at a defined target, when i ask the program to look for tax (which dont exist) the program showed nothing, then i ask the program to get the subtotal of rent (which exists). The program cant make the changes.
i am relatively new to all this.... so thanks again for helping! :)
from tkinter import *
import openpyxl as xl
window = Tk()
window.title("Excel Automation") # rename the title
def define_subtotal():
file_name = str(file_name_input_field.get()) # Collects the text from the text entry box
sheet_name = str(sheet_name_label_name_input_field.get()) # Collects the text from the text entry box
global wb # declare Workbook as global variable
wb = xl.load_workbook(file_name) # define workbook
sheet = wb[sheet_name] # Define sheet name
col_num = int(search_column_input_field.get())
search_phrase = search_phrase_input_field.get()
offset_col = int(offset_col_input_field.get())
target_col_num = int(target_col_input_field.get())
target_row_num = int(target_row_input_field.get())
total = 0
for row in range(2, sheet.max_row + 1):
cell = sheet.cell(row, col_num)
if cell.value is None:
continue
else:
if search_phrase.casefold() in str(cell.value).casefold():
total += cell.offset(column=offset_col).value
total_description = sheet.cell(target_row_num, target_col_num + 1)
total_description.value = "Subtotal of : " + search_phrase
total_cell = sheet.cell(target_row_num, target_col_num)
total_cell.value = total
output.delete(0.0, END)
output.insert(END, "Subtotal for " + search_phrase + " defined")
else:
continue
def execute():
output.delete(0.0, END) # clear the text box
new_file_name = new_file_input_field.get()
output.insert(END, "Calculations complete!")
wb.save(new_file_name + ".xlsx")
def import_excel_file():
output.delete(0.0, END) # clear the text box
output.insert(END, "File imported")
sheet_name_label_name_input_field.config (state='disabled')
import_button.config (state='disabled')
file_name_input_field.config (state='disabled')
def close_window(): # exit function
window.destroy()
exit()
### CONTENTS
file_name_label = Label(window, text="File Name:")
file_name_input_field = Entry(window, width=38, borderwidth=2)
sheet_name_label = Label(window, text="Sheet Name:")
sheet_name_label_name_input_field = Entry(window, width=38, borderwidth=2)
import_button = Button(window, text="Import", padx=35, pady=0, command=import_excel_file)
search_phrase_label = Label(window, text="Search Phrase:")
search_phrase_input_field = Entry(window, width=38, borderwidth=2)
search_column_label = Label(window, text="Search Column:")
search_column_input_field = Entry(window, width=38, borderwidth=2)
offset_col_label = Label(window, text="Offset Column:")
offset_col_input_field = Entry(window, width=38, borderwidth=2)
target_col_label = Label(window, text="Target Column:")
target_col_input_field = Entry(window, width=38, borderwidth=2)
target_row_label = Label(window, text="Target Row:")
target_row_input_field = Entry(window, width=38, borderwidth=2)
new_file_label = Label(window, text="Name of New file:")
new_file_input_field = Entry(window, width=38, borderwidth=2)
define_subtotal_button = Button(window, text="Define Subtotal", padx=5, pady=0, command=define_subtotal)
execute_button = Button(window, text="Execute", padx=5, pady=0, command=execute)
# contents Column 2
status_label = Label(window, text="Status:")
output = Text(window, width=50, height=25, wrap=WORD, bg="white") # wrap=WORD : wrap text when in overflow.
output.insert(END, "Drag and drop file into project file\n"
"Define File Name and Sheet Name\n"
"Example: filename.xlsx /.xlsm/ xltx/.xltm")
exit_button = Button(window, text="exit", width=14, command=close_window)
### THE GRID
file_name_label.grid(row=0, column=0, columnspan=2, padx=0, pady=0, sticky=W)
file_name_input_field.grid(row=1, column=0, columnspan=2, padx=5, pady=3, sticky=W)
sheet_name_label.grid(row=2, column=0, columnspan=2, padx=0, pady=0, sticky=W)
sheet_name_label_name_input_field.grid(row=3, column=0, columnspan=2, padx=5, pady=3, sticky=W)
import_button.grid(row=4, column=0, columnspan=2, sticky=W, padx=5)
search_phrase_label.grid(row=5, column=0, columnspan=2, padx=0, pady=0, sticky=W)
search_phrase_input_field.grid(row=6, column=0, columnspan=2, padx=5, pady=5, sticky=W)
search_column_label.grid(row=7, column=0, columnspan=2, padx=0, pady=0, sticky=W)
search_column_input_field.grid(row=8, column=0, columnspan=2, padx=5, pady=5, sticky=W)
offset_col_label.grid(row=9, column=0, columnspan=2, padx=0, pady=0, sticky=W)
offset_col_input_field.grid(row=10, column=0, columnspan=2, padx=5, pady=5, sticky=W)
target_col_label.grid(row=11, column=0, columnspan=2, padx=0, pady=0, sticky=W)
target_col_input_field.grid(row=12, column=0, columnspan=2, padx=5, pady=5, sticky=W)
target_row_label.grid(row=13, column=0, columnspan=2, padx=0, pady=0, sticky=W)
target_row_input_field.grid(row=14, column=0, columnspan=2, padx=5, pady=5, sticky=W)
new_file_label.grid(row=15, column=0, columnspan=2, padx=0, pady=0, sticky=W)
new_file_input_field.grid(row=16, column=0, columnspan=2, padx=5, pady=5, sticky=W)
define_subtotal_button.grid(row=17, column=0, sticky=W, padx=5)
# GRID column 1
execute_button.grid(row=17, column=1, sticky=W, padx=5)
# GRID Column 2
status_label.grid(row=0, column=2, padx=5, sticky=W)
output.grid(row=1, column=2, rowspan=25, padx=5, sticky=NE)
exit_button.grid(row=17, column=2, sticky=E)
window.mainloop()
[enter image description here][1]
may be it will be a good option to use
try:
your code
except:
pass
And run your code inside of this from which you want to skip the error with this try except. if any exception happened then it will ignore this and will be running.
I want to have a GUI with 2 buttons. Once clicked on either button, I want to see a new GUI which has a button to go back to the main GUI with the two buttons again.
This is what I've got right now but the 'Go back' button doesn't do anything. How can I go back to my first page using tkinter?
from tkinter import *
root = Tk()
root.title('Frames')
root.geometry('500x250+300+300')
# Position frame
frame = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame.pack(padx=10, pady=50)
# What do the buttons do
def bad():
frame.grid_forget()
b.grid_forget()
b2.grid_forget()
slechtekeuze = Label(frame, text='Bad choice')
slechtekeuze.grid(row=0, column=0, columnspan=2)
# Option to got back
homepage = Button(frame, text='Go back', command=back)
homepage.grid(row=1, column=0, columnspan=2, pady=10)
def good():
frame.grid_forget()
b.grid_forget()
b2.grid_forget()
slechtekeuze = Label(frame, text='Good choice')
slechtekeuze.grid(row=0, column=0, columnspan=2)
# Option to go back
homepage = Button(frame, text='Terug', command=back)
homepage.grid(row=1, column=0, columnspan=2, pady=10)
def back():
frame.grid_forget()
frame1 = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame1.pack(padx=10, pady=50)
b = Button(frame1, text="Don't click!!!", fg='red', command=bad)
b2 = Button(frame1, text='Click!!!', fg='green', command=good)
b.grid(row=0, column=0, padx=3)
b2.grid(row=0, column=1, padx=3)
# Create the buttons and put them in the frame
b = Button(frame, text="Don't click!!!", fg='red', command=bad)
b2 = Button(frame, text='Click!!!', fg='green', command=good)
b.grid(row=0, column=0, padx=3)
b2.grid(row=0, column=1, padx=3)
root.mainloop()
It does work, expand your screen a bit. The frames get added below.
I've edited it a bit as much in your style as possible:
from tkinter import *
root = Tk()
root.title('Frames')
root.geometry('500x250+300+300')
# Position frame
frame = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame.pack(padx=10, pady=50)
# What do the buttons do
def bad(frame):
frame.destroy()
frame = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame.pack(padx=10, pady=50)
slechtekeuze = Label(frame, text='Bad choice')
slechtekeuze.grid(row=0, column=0, columnspan=2)
# Option to got back
homepage = Button(frame, text='Go back', command=lambda:back(frame))
homepage.grid(row=1, column=0, columnspan=2, pady=10)
def good(frame):
frame.destroy()
frame = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame.pack(padx=10, pady=50)
slechtekeuze = Label(frame, text='Good choice')
slechtekeuze.grid(row=0, column=0, columnspan=2)
# Option to go back
homepage = Button(frame, text='Terug', command=lambda:back(frame))
homepage.grid(row=1, column=0, columnspan=2, pady=10)
def back(frame):
frame.destroy()
frame = LabelFrame(root, text='Such a dilemma', padx=25, pady=25)
frame.pack(padx=10, pady=50)
b = Button(frame, text="Don't click!!!", fg='red', command=lambda:bad(frame))
b2 = Button(frame, text='Click!!!', fg='green', command=lambda:good(frame))
b.grid(row=0, column=0, padx=3)
b2.grid(row=0, column=1, padx=3)
# Create the buttons and put them in the frame
b = Button(frame, text="Don't click!!!", fg='red', command=lambda:bad(frame))
b2 = Button(frame, text='Click!!!', fg='green', command=lambda:good(frame))
b.grid(row=0, column=0, padx=3)
b2.grid(row=0, column=1, padx=3)
root.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.
I am little bit comfused with grid system in tkinter Python. Can anyone show how to make it in right way?! ListBox and Label items positions are not in the places where I expexted to see them.
CODE:
self.third_label = Label(self, text="TEXT")
self.third_label.grid(row=2, column=0, columnspan=4, padx=10, pady=10, sticky=W)
self.fourth_label = Label(self, text="LONG TEXT")
self.fourth_label.grid(row=2, column=1, columnspan=4, padx=10, pady=10, sticky=W)
self.fifth_label = Label(self, text="SOME TEXT")
self.fifth_label.grid(row=2, column=2, columnspan=6, padx=10, pady=10, sticky=W)
self.sixth_label = Label(self, text="BIG TEXT")
self.sixth_label.grid(row=2, column=3, columnspan=4, padx=10, pady=10, sticky=W)
self.first_listbox = Listbox(self, width=40, selectmode=EXTENDED)
self.first_listbox.grid(row=3, column=0, columnspan=4, padx=10, pady=10, sticky=W)
self.second_listbox = Listbox(self, width=40, selectmode=EXTENDED)
self.second_listbox.grid(row=3, column=2, columnspan=4, padx=10, pady=10, sticky=W)
self.third_listbox = Listbox(self, width=40, selectmode=EXTENDED)
self.third_listbox.grid(row=3, column=4, columnspan=4, padx=10, pady=10, sticky=W)
self.fourth_listbox = Listbox(self, width=40, selectmode=EXTENDED)
self.fourth_listbox.grid(row=3, column=6, columnspan=4, padx=10, pady=10, sticky=W)
What I have right now:
Just Example:
The grid system works fine. The problem is your columnspans, which don't make much sense. You're gridding the widgets into certain column positions then giving them a columnspan that is beyond the range of where the next widget is to be gridded so on and so forth.
Small example:
import string
import tkinter as tk
root = tk.Tk()
for i in range(3):
tk.Label(root, text=string.ascii_letters).grid(row=0, column=i)
tk.Listbox(root, width=40).grid(row=1, column=i)
root.mainloop()
Edit from comments (for listbox size):
To get the number of lines in a listbox you can use the .size() method.
Image: