How to scroll through data being displayed on a Tkinter Window? - python

So I am creating a small data handler program that essentially allows the user to turn in a form that takes in values such as your address, city, name, email, etc. Pressing "View Personnel Data" opens up another Tkinter window which displays all the data that users have previously entered in (data which is stored in a text file and then read from to display the data). I have organized the data in columns in a secondary Tkinter window based on what the data is (e.g. address, city, etc). Of course, eventually, there won't be enough room in the windows to display all entries, and as such the user would want to be able to scroll through them. As a newbie to Tkinter and python in general, I am not sure as to how I would go about doing this. Below I have attached pictures of the windows that are displayed in my program and my code.
My code:
import tkinter as t
root = t.Tk()
root.title("Data Handler")
root.geometry('250x250')
#class viewPersons():
#def open(self):
def addPerson():
data = open('data.txt', 'a')
name = name_var.get()
email = email_var.get()
age = age_var.get()
state = state_var.get()
city = city_var.get()
address = address_var.get()
print(name+','+email+','+age+','+state+','+city+','+address)
data.write(name+','+email+','+age+','+state+','+city+','+address+'\n')
data.close()
viewopen=False
def viewWindow():
global viewopen
def on_close():
global viewopen
viewopen = False
view.destroy()
def onFrameConfigure(primarycanvas):
primarycanvas.configure(scrollregion=primarycanvas.bbox("all"))
if viewopen is False:
viewopen=True
view = t.Tk()
view.geometry('800x300')
primarycanvas = t.Canvas(view, borderwidth=0, background='#ffffff')
frame = t.Frame(primarycanvas, background='#ffffff')
vsb = t.Scrollbar(view, orient='vertical', command=primarycanvas.yview)
primarycanvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
primarycanvas.pack(side="left", fill="both", expand=True)
primarycanvas.create_window((4, 4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, primarycanvas=primarycanvas: onFrameConfigure(primarycanvas))
t.Label(frame,text='N͟a͟m͟e͟',borderwidth=2,relief='groove',font=(20)).grid(row=0,column=0)
t.Label(frame, text='E͟m͟a͟i͟l͟',borderwidth=2,relief='groove',font=(20)).grid(row=0, column=1)
t.Label(frame, text='A͟g͟e͟',borderwidth=2,relief='groove',font=(20)).grid(row=0, column=2)
t.Label(frame, text='S͟t͟a͟t͟e͟',borderwidth=2,relief='groove',font=(20)).grid(row=0, column=3)
t.Label(frame, text='C͟i͟t͟y͟',borderwidth=2,relief='groove',font=(20)).grid(row=0, column=4)
t.Label(frame, text='A͟d͟d͟r͟e͟s͟s͟',borderwidth=2,relief='groove',font=(20)).grid(row=0, column=5)
class Person():
def __init__(self, name, email, age, state, city, address, rowcounter):
self.name = name
self.email = email
self.age = age
self.state = state
self.city = city
self.address = address
self.rowcounter = rowcounter
def display(self):
t.Label(frame, text=self.name,font=(20)).grid(row=self.rowcounter,column=0)
t.Label(frame,text=self.email,font=(20)).grid(row=self.rowcounter,column=1)
t.Label(frame, text=self.age,font=(20)).grid(row=self.rowcounter, column=2)
t.Label(frame, text=self.state,font=(20)).grid(row=self.rowcounter, column=3)
t.Label(frame, text=self.city,font=(20)).grid(row=self.rowcounter, column=4)
t.Label(frame, text=self.address,font=(20)).grid(row=self.rowcounter, column=5)
data = open('data.txt', 'r+')
rowcounter=1
info = data.readlines()
persons = {}
person_id = 0
for x in info:
split = x.strip().split(',')
print(split)
person_id += 1
persons[person_id] = Person(split[0],split[1],split[2],split[3],split[4],split[5], rowcounter)
persons[person_id].display()
rowcounter += 1
print(persons)
data.close()
view.protocol('WM_DELETE_WINDOW', on_close)
view.mainloop()
name_var = t.StringVar()
email_var = t.StringVar()
age_var = t.StringVar()
state_var = t.StringVar()
city_var = t.StringVar()
address_var = t.StringVar()
t.Label(root, text='Name:').grid(row=0,padx=4)
name_ent = t.Entry(root, textvariable=name_var).grid(row=0,column=1,pady=4)
t.Label(root, text='Email:').grid(row=1,padx=4)
email_ent = t.Entry(root, textvariable=email_var).grid(row=1,column=1,pady=4)
t.Label(root, text='Age:').grid(row=2, padx=4)
age_ent = t.Entry(root, textvariable=age_var).grid(row=2,column=1,pady=4)
t.Label(root, text='State:').grid(row=3, padx=4)
state_ent = t.Entry(root, textvariable=state_var).grid(row=3,column=1,pady=4)
t.Label(root, text='City:').grid(row=4,padx=4)
city_ent = t.Entry(root, textvariable=city_var).grid(row=4,column=1,pady=4)
t.Label(root, text='Address:').grid(row=5,padx=4)
address_ent = t.Entry(root, textvariable=address_var).grid(row=5,column=1,pady=4)
t.Button(root, text='Submit',width=15,command=addPerson).grid(row=6,columnspan=2,ipadx=10)
t.Button(root,text='View Personnel Data',width=15,command=viewWindow).grid(row=7,columnspan=2,ipadx=10)
root.mainloop()

Related

Python GUI App is not functioning well, help me fix it?

Here's my code of a gui app using tkinter library, it creats tables and prints orders for each table and gives the ability to edit orders on every table. the goal of it to know what did each table order. but editing the orders doesn't seem to work at all, I need help fixing it.
import tkinter as tk
class TableOrdersApp:
def __init__(self, master):
self.tables = []
self.table_list = tk.Listbox(master)
self.table_list.pack(side=tk.LEFT, fill=tk.BOTH)
self.table_list.bind("<<ListboxSelect>>", self.refresh_label)
self.orders_label = tk.Label(master, text="", anchor=tk.W, justify=tk.LEFT, wraplength=400)
self.orders_label.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.button_frame = tk.Frame(master)
self.button_frame.pack(side=tk.RIGHT)
self.add_button = tk.Button(self.button_frame, text="Add Table", command=self.add_table)
self.add_button.pack(side=tk.TOP)
self.remove_button = tk.Button(self.button_frame, text="Remove Table", command=self.remove_table)
self.remove_button.pack(side=tk.TOP)
self.edit_button = tk.Button(self.button_frame, text="Edit Order", command=self.edit_order)
self.edit_button.pack(side=tk.TOP)
self.remove_order_button = tk.Button(self.button_frame, text="Remove Order", command=self.remove_order)
self.remove_order_button.pack(side=tk.TOP)
def add_table(self):
self.tables.append([])
self.table_list.insert(tk.END, "Table {}".format(len(self.tables)))
def remove_table(self):
index = self.table_list.curselection()[0]
self.tables.pop(index)
self.table_list.delete(index)
def refresh_label(self, event=None):
self.orders_label.config(text="\n".join(self.tables[self.table_list.curselection()[0]]))
def edit_order(self):
index = self.table_list.curselection()[0]
orders = self.tables[index]
if self.orders_label.select_present():
start_index = self.orders_label.index(tk.SEL_FIRST)
end_index = self.orders_label.index(tk.SEL_LAST)
selected_text = self.orders_label.selection_get()
num_newlines = selected_text.count("\n")
order_index = start_index.split(".")[0] - 1 - num_newlines
new_order = tk.simpledialog.askstring("Edit Order", "Enter the new order:")
orders[order_index] = new_order
self.refresh_label()
def remove_order(self):
index = self.table_list.curselection()[0]
orders = self.tables[index]
start_index = self.orders_label.index(tk.SEL_FIRST)
end_index = self.orders_label.index(tk.SEL_LAST)
num_newlines = self.orders_label.get(start_index, end_index).count("\n")
order_index = start_index.split(".")[0] - 1 - num_newlines
orders.pop(order_index)
self.refresh_label()
# Create the main window
root = tk.Tk()
# Create an instance of the TableOrdersApp class
app = TableOrdersApp(root)
# Run the main loop of the app
root.mainloop()
I tried to make it print a label and make it editable using "edit order" button, but the button itself doesn't seem to work, and I want it to print "Empty" if the table has no orders how can i do that.
Look in edit_order and remove_order function. Must easier to write less coding.
Here is code:
import tkinter as tk
class TableOrdersApp:
def __init__(self, master):
self.tables = []
self.table_list = tk.Listbox(master)
self.table_list.pack(side=tk.LEFT, fill=tk.BOTH)
self.table_list.bind("<<ListboxSelect>>", self.refresh_label)
self.orders_label = tk.Label(master, text="", anchor=tk.W, justify=tk.LEFT, wraplength=400)
self.orders_label.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.button_frame = tk.Frame(master)
self.button_frame.pack(side=tk.RIGHT)
self.add_button = tk.Button(self.button_frame, text="Add Table", command=self.add_table)
self.add_button.pack(side=tk.TOP)
self.remove_button = tk.Button(self.button_frame, text="Remove Table", command=self.remove_table)
self.remove_button.pack(side=tk.TOP)
self.edit_button = tk.Button(self.button_frame, text="Edit Order", command=self.edit_order)
self.edit_button.pack(side=tk.TOP)
self.remove_order_button = tk.Button(self.button_frame, text="Remove Order", command=self.remove_order)
self.remove_order_button.pack(side=tk.TOP)
def add_table(self):
self.tables.append([])
self.table_list.insert(tk.END, "Table {}".format(len(self.tables)))
def remove_table(self):
index = self.table_list.curselection()[0]
self.tables.pop(index)
self.table_list.delete(index)
def refresh_label(self, event=None):
self.orders_label.config(text="\n".join(self.tables[self.table_list.curselection()[0]]))
def edit_order(self):
index = self.table_list.curselection()[0]
orders = self.table_list.get(index)
print(index)
order = orders
self.orders_label.configure(text=order)
#if self.orders_label.select_present():
#start_index = self.orders_label.index(tk.SEL_FIRST)
#end_index = self.orders_label.index(tk.SEL_LAST)
#selected_text = self.orders_label.selection_get()
#num_newlines = selected_text.count("\n")
#order_index = start_index.split(".")[0] - 1 - num_newlines
#new_order = tk.simpledialog.askstring("Edit Order", "Enter the new order:")
#orders[order_index] = new_order
#self.refresh_label()
def remove_order(self):
remove_orders = self.table_list.curselection()
self.table_list.delete(remove_orders)
self.orders_label.configure(text="")
#index = self.table_list.curselection()[0]
#orders = self.tables[index]
#start_index = self.orders_label.index(tk.SEL_FIRST)
#end_index = self.orders_label.index(tk.SEL_LAST)
#num_newlines = self.orders_label.get(start_index, end_index).count("\n")
#order_index = start_index.split(".")[0] - 1 - num_newlines
#orders.pop(order_index)
#self.refresh_label()
# Create the main window
root = tk.Tk()
# Create an instance of the TableOrdersApp class
app = TableOrdersApp(root)
# Run the main loop of the app
root.mainloop()
Result when executes:
Result when selected:
Result when removed order:

Class Object is being referenced as a String

I am writing code to build a basic employee management software with GUI. When I load sample data, I believe they are being created as Class Objects (Employee) because when I debug I can see that all of the arguments are passed and the object is created. HOWEVER, when I try to modify them later (such as hired status), it returns an error 'str' object has no attribute 'hired_status'
Employee Class:
"""Create Employee class so all employees can be Employee Objects"""
def __init__(self, fname='', lname='', phone='', email='', job='', interview_rating=0, hired_status='N'):
self.first = fname
self.last = lname
self.phone_number = phone
self.email_address = email
self.interview = interview_rating
self.__emp_job = job
self.hired_status = hired_status
#property
def first_name(self):
return self.__first
#first_name.setter
def first_name(self, fname):
if fname.isalpha() and len(fname) >= 1:
self.__first = fname.capitalize()
else:
self.__first = 'Unknown'
#property
def last_name(self):
return self.__last
#last_name.setter
def last_name(self, lname):
if lname.isalpha() and len(lname) >= 1:
self.__last = lname.capitalize()
else:
self.__last = 'Unknown'
#property
def email_address(self):
return self.__email_address
#email_address.setter
def email_address(self, email):
if len(email) >=1 and '#' in email:
self.__email_address = email
else:
self.__email_address = 'Unknown'
#property
def phone_number(self):
return self.__phone_number.format(str)
#phone_number.setter
def phone_number(self, phone):
if len(phone) >= 1:
self.__phone_number = phone
else:
self.__phone_number = 'Unknown'
#property
def job(self):
return self.__emp_job
#job.setter
def job(self, job):
self.__emp_job = job
#property
def hired_status(self):
return self.__hired_status
#hired_status.setter
def hired_status(self, hired):
self.__hired_status = hired
def __str__(self):
return f'{self.first_name},{self.last_name},{self.phone_number},{self.email_address},{self.job},' \
f'{self.hired_status}'
Main Class:
def load_employees():
"""
Loads same employees from the text file.
- Creates an Employee object for each employee listed in the file.
- Retrieves comma-separated values from each line and assigns it to the corresponding arg in Employee()
- Adds the new employee object to the list of current employees.
- Displays the employees on the screen for the user.
"""
global first_name, last_name, phone, email, job, new_employee, current_employees, hired_status
current_employees = []
with open('employees.txt', 'r') as file:
for f in file:
first_name, last_name, phone, email, job, hired_status = f.split(',')
sample_employee = Employee(first_name, last_name, phone, email, job, hired_status)
sample_employee.first_name = first_name
sample_employee.last_name = last_name
sample_employee.phone_number = phone
sample_employee.email_address = email
sample_employee.job = job
sample_employee.hired_status = hired_status
current_employees.append(f)
emp_list.insert(END, f)
Trying to hire
def hire_candidate():
global first_name, last_name, phone, email, job, new_employee, current_employees, edit_mode, hired_status, emp_list
new_employee = emp_list.get(ANCHOR)
new_employee.hired_status = 'Y'
adding new employee with the GUI
def save_new_employee():
"""
When user clicks "Save Employee" the program will create or edit an Employee object.
- A new Employee will be added to the list of current employees and appear in the GUI.
- If editing, the Employee object will be updated with the new information.
- The user is prompted with a message saying they have added or updated an Employee.
- The Employee Management form will then clear all textboxes.
"""
global first_name, last_name, phone, email, job, new_employee, current_employees, edit_mode, hired_status
global applicant_first_tbx, applicant_last_tbx, applicant_phone_tbx, applicant_email_tbx, jobs_cbx
new_employee = None
new_employee = Employee(first_name, last_name, phone, email, job, hired_status)
new_employee.first_name = applicant_first_tbx.get()
new_employee.last_name = applicant_last_tbx.get()
new_employee.phone_number = applicant_phone_tbx.get()
new_employee.email_address = applicant_email_tbx.get()
new_employee.job = job
if edit_mode:
x = emp_list.curselection()
current_employees[edit_index] = x
emp_list.delete(x)
emp_list.insert(edit_index, new_employee)
current_employees.pop(edit_index)
current_employees.append(new_employee)
edit_mode = False
messagebox.showinfo('Employee Information Updated.', f'Information for {new_employee.first_name} '
f'{new_employee.last_name} has been updated.')
else:
current_employees.append(new_employee)
emp_list.insert(END, new_employee)
messagebox.showinfo('New Employee Added', f'{new_employee.first_name} {new_employee.last_name} '
f'has been added to your roster.')
applicant_first_tbx.delete(0, END)
applicant_last_tbx.delete(0, END)
applicant_phone_tbx.delete(0, END)
applicant_email_tbx.delete(0, END)
Creating the relevant GUI
# create the main program window
win = Tk()
win.title('Employee Management Form')
win.config(bg='skyblue', pady=20, padx=50)
# global variables
current_employees = []
edit_mode = False
first_name = StringVar()
last_name = StringVar()
phone = StringVar()
email = StringVar()
job = StringVar()
hired_status = StringVar()
job_titles = ['Cook', 'Dishwasher', 'Server']
food_handler = ['Yes', 'No']
cook_certs = {1: 'Basic', 2: 'Advanced'}
interview_scores = [1, 2, 3, 4, 5]
y_offset = 10
color = 'skyblue'
new_employee = None
edit_index = 0
employeeManagement = True
# options menu
menu_bar = Menu(win)
win.config(menu=menu_bar)
win.iconbitmap('emgmt.ico')
# Create a menu bar with required cascades and commands
file_menu = Menu(menu_bar, tearoff=False)
view = Menu(menu_bar, tearoff=False)
menu_bar.add_cascade(label='File', menu=file_menu)
# Saves the information entered into the textboxes as a new employee, or overwrites an employee if editing
file_menu.add_command(label='Save Employee', command=save_new_employee)
# Turns on Edit Mode so user can modify information of an existing employee
file_menu.add_command(label='Edit Employee', command=edit_employee)
# Deletes employee obj from the data structure and removes their name from the GUI
file_menu.add_command(label='Delete Employee', command=delete_employee)
# updates the text file of employees, so upon reopening the program, all changes made previously are reflected
file_menu.add_command(label='Save All Changes', command=save_all_changes)
# Adds the option for the user to switch between employee management and the interview scorecard
menu_bar.add_cascade(label='View', menu=view)
view.add_command(label='Employee Management', command=employee_mgmt)
view.add_command(label='Employee Rating', command=employee_rating)
# frame to display list of current employees. Always visible as per instructions
emp_list_frm = Frame(win, bg='skyblue')
emp_list_frm.pack()
# create the listbox of employees
emp_list_lbl = Label(emp_list_frm, text='Current Employees', bg='systembuttonface', width=30, justify=CENTER)
emp_list_lbl.grid(row=0, column=1, sticky=S)
emp_list = Listbox(emp_list_frm, width=75, listvariable=current_employees)
emp_list.grid(row=1, columnspan=3)
# employee management frame to add, edit, and delete employees
em_frame = Frame(win, bg='skyblue')
em_frame.pack()
# create layout for job application data
applicant_first_lbl = Label(em_frame, text='First Name:', justify=LEFT, pady=y_offset, bg=color)
applicant_first_lbl.grid(row=2, column=0, sticky=W)
applicant_first_tbx = Entry(em_frame, justify=LEFT, width=30, textvariable=first_name)
applicant_first_tbx.grid(row=2, column=1, sticky=W)
applicant_first_tbx.bind('<Key>', name_keys)
applicant_last_lbl = Label(em_frame, text='Last Name:', justify=LEFT, pady=y_offset, bg=color)
applicant_last_lbl.grid(row=3, column=0, sticky=W)
applicant_last_tbx = Entry(em_frame, justify=LEFT, width=30, textvariable=last_name)
applicant_last_tbx.grid(row=3, column=1, sticky=W)
applicant_last_tbx.bind('<Key>', name_keys)
applicant_phone_lbl = Label(em_frame, text='Phone Number:', justify=LEFT, pady=y_offset, bg=color)
applicant_phone_lbl.grid(row=4, column=0, sticky=W)
applicant_phone_tbx = Entry(em_frame, justify=LEFT, width=30, textvariable=phone)
applicant_phone_tbx.grid(row=4, column=1, sticky=W)
applicant_phone_tbx.bind('<Key>', phone_keys)
applicant_email_lbl = Label(em_frame, text='Email:', justify=LEFT, pady=y_offset, bg=color)
applicant_email_lbl.grid(row=5, column=0, sticky=W)
applicant_email_tbx = Entry(em_frame, justify=LEFT, width=30, textvariable=email)
applicant_email_tbx.grid(row=5, column=1, sticky=W)
# create dropdown list for food handlers card
food_handler_label = Label(em_frame, text='Food Handler Card:', justify=LEFT, pady=y_offset, bg=color)
food_handler_label.grid(row=6, column=0, sticky=W)
food_handler_cbx = ttk.Combobox(em_frame, values=food_handler, width=10)
food_handler_cbx.grid(row=7, column=0, sticky=W)
# create dropdown list for applied positions
job_applied_label = Label(em_frame, text='Select Job:', justify=LEFT, pady=y_offset, bg=color)
job_applied_label.grid(row=8, column=0, columnspan=3, sticky=W)
jobs_cbx = ttk.Combobox(em_frame, values=job_titles, width=15)
jobs_cbx.grid(row=9, column=0, sticky=W)
jobs_cbx.bind('<<ComboboxSelected>>', add_job_applied)
# Textbox showing list of all jobs the employee applied for
jobs_applied_txt = Entry(em_frame, justify=LEFT, width=25, textvariable=job_titles)
jobs_applied_txt.grid(row=9, columnspan=2, sticky=E)
# Highest Cook cert
cook_cert_label = Label(em_frame, text='If Cook, select highest certification:', justify=LEFT,
pady=y_offset, bg=color)
cook_cert_label.grid(row=11, column=0, columnspan=3, sticky=W)
# If applying for Cook, Buttons to show the highest level cooking cert
basic_btn = Radiobutton(em_frame, variable=cook_certs, text='Basic', value=1, bg=color, indicatoron=1, state=DISABLED)
basic_btn.grid(row=12, column=0, sticky=W)
advanced_btn = Radiobutton(em_frame, variable=cook_certs, text='Advanced', value=2, bg=color, indicatoron=1, padx=2,
state=DISABLED)
advanced_btn.grid(row=12, column=1, sticky=W)
# Creates a frame for Rating System
rating_frame = Frame(win, bg='skyblue')
rating_lbl = Label(rating_frame, bg=color, text='Interview Rating Form:\n'
'Rate an Employee from 1 to 5, where 1 is the '
'worst and 5 is the best'' in the following categories.')
rating_lbl.grid(row=2, column=0, columnspan=3)
comms_rate_lbl = Label(rating_frame, bg=color, text='1. Verbal/Communication Skills')
comms_rate_lbl.grid(row=3, column=0, sticky=W)
comms_cbx = ttk.Combobox(rating_frame, values=interview_scores, width=10)
comms_cbx.grid(row=4, column=0, sticky=W)
personal_rate_lbl = Label(rating_frame, bg=color, text='2. Interpersonal Skills and Friendliness')
personal_rate_lbl.grid(row=5, column=0, sticky=W)
personal_cbx = ttk.Combobox(rating_frame, values=interview_scores, width=10)
personal_cbx.grid(row=6, column=0, sticky=W)
math_lbl = Label(rating_frame, bg=color, text='3. Math/Problem Solving Skills')
math_lbl.grid(row=7, column=0, sticky=W)
math_cbx = ttk.Combobox(rating_frame, values=interview_scores, width=10)
math_cbx.grid(row=8, column=0, sticky=W)
exp_lbl = Label(rating_frame, bg=color, text='4. Applicable World Experience')
exp_lbl.grid(row=9, column=0, sticky=W)
exp_cbx = ttk.Combobox(rating_frame, values=interview_scores, width=10)
exp_cbx.grid(row=10, column=0, sticky=W)
interview_average_btn = Button(rating_frame, bg='gray', text='Calculate Interview Average',
command=lambda: calculate_interview_average(interview_average_btn))
interview_average_btn.grid(row=11, column=0, columnspan=3, sticky=W, pady=8,)
interview_average_tbx = Entry(rating_frame, bg='white', width=10)
interview_average_tbx.grid(row=11, column=0, sticky=E)
hire_btn = Button(rating_frame, bg='gold', text='Hire Candidate', state=DISABLED, command=hire_candidate)
hire_btn.grid(row=12, column=0, sticky=W)
The idea is that you click and employee form a listbox, then click a button to hire them. I think it is returning the string from the listbox, but I want it to return the object in that location.
Error message
File "C:\Users\Jack\PycharmProjects\Class_Project_jxhawki1\employee_management.py", line 188, in hire_candidate
new_employee.hired_status = 'Y'
AttributeError: 'str' object has no attribute 'hired_status'
There are several problems with the code you have shown. First, your code relies on, in my humble opinion, too many global variables that are not necessary or desirable. Second, while technically all right the way you are mixing grid and pack geometries within the same window will work, it is a dangerous practice. I much prefer sticking with one geometry throughout everything. Finally, I believe your basic problem is that you have provided no data structure to correlate the string value returned from listbox select function to the specific employee instance containing the selected employee's data. The following is not a complete solution to your overall application needs, but does clean up several of the above issues.
First, a rewrite of your Employee class
class Employee:
"""Create Employee class so all employees can be Employee Objects"""
def __init__(self, fname= 'Unknown', lname= 'Unknown', phone= 'Unknown', email= 'Unknown', job= '', interview_rating= 0, hired_status= False):
self._first = None
self._last = None
self._emAdr = None
self._phnNo = None
self._status = False
self._job = None
self._intrvRate = int(interview_rating)
self.first_name = fname
self.last_name = lname
self.phone_number = phone
self.email_address = email
self.employee_job = job
self.hired_status = hired_status
#property
def first_name(self):
return self._first
#first_name.setter
def first_name(self, fname):
try:
if fname.isalpha() and len(fname) >= 1:
self._first = fname.capitalize()
except:
raise ValueError(f"First Name '{fname}' must be alpha and be at least 1 character long")
#property
def last_name(self):
return self._last
#last_name.setter
def last_name(self, lname):
if lname.isalpha() and len(lname) >= 1:
self._last = lname.capitalize()
else:
raise ValueError(f"Last Name '{lname}' must be alpha and be at least 1 character long")
#property
def full_name(self):
return f"{self.last_name}, {self.first_name}"
#property
def email_address(self):
return self._emAdr
#email_address.setter
def email_address(self, email):
if email == '':
self.emAdr = 'Unknown'
elif '#' in email and len(email) >= 1:
self._emAdr = email
else:
raise ValueError(f"Email Address '{email}' must contain an '#' and be at least 1 character long")
#property
def phone_number(self):
return self._phnNo
#phone_number.setter
def phone_number(self, phone):
if len(phone) == 0:
self._phnNo = 'Unknown'
elif len(phone) >= 1:
self._phnNo = phone
else:
raise ValueError(f"Phone Number '{phone}' must be at least 1 character long")
#property
def employee_job(self):
return self._job
#employee_job.setter
def employee_job(self, job):
self._job = job
#property
def hired_status(self):
return self._status
#hired_status.setter
def hired_status(self, status):
if isinstance(status, bool):
self._status = status
else:
raise ValueError(f"Hiring Status '{status}' must be either 'True' or 'False'")
#property
def hire(self):
self.hired_status = True
#property
def fire(self):
self.hired_status = False
def __repr__(self):
return f'{self.first_name}, {self.last_name}, {self.phone_number}, {self.email_address}, {self.employee_job}, {self.hired_status}'
An updated load data function:
def load_employees(fn):
"""
Loads employees from text file fn.
- Retrieves comma-separated values from each line and assigns it to the corresponding arg in Employee()
- Adds the employee object to the employee_dict.
"""
employee_dict = dict()
with open(fn, 'r') as file:
for l in file.readlines():
itms = l.split(',')
emp = Employee(fname= itms[0].strip(),
lname = itms[1].strip(),
phone= itms[2].strip(),
email = itms[3].strip(),
job = itms[4].strip(),
interview_rating = itms[5].strip(),
hired_status = True if itms[6].strip().lower() == 'y' else False)
employee_dict[emp.full_name] = emp
return employee_dict
A couple of Enumerated Constant classes
class job_titles(Enum):
Cook = auto()
Dishwasher = auto()
Server = auto()
class food_handlers(Enum):
Cook = True
Dishwasher = False
Server = True
class cook_certs(Enum):
Basic = 1
Advanced = 2
A new class to manage the GUI interface
# Class to display the Employee Gui and Manage all related employee methods
class EmployeeForm():
def __init__(self, employee_list):
self.emp_list = employee_list
self.selected_employee = None
self.win = tk.Tk()
self.win.title("Employee Management Form")
self.win.config(bg='skyblue', pady=20, padx=50)
self.build_menuBar(self.win)
self.build_list_frame(self.win)
self.win.mainloop()
def do_nothing(self):
#Stub for menu items not yetbimplements
pass
def get_currewnt_employees(self):
pass
def build_menuBar(self, frm):
""" Format the Menu bar """
def add_command(mnu, itm):
mnu.add_command(label= itm[0], command= itm[1])
def add_sub_menu(mnu, cmd_dict):
for ky in cmd_dict.keys():
if len(cmd_dict[ky]) > 0:
mi = tk.Menu(mnu, tearoff= 0)
mnu.add_cascade(label=ky, menu=mi)
for itm in cmd_dict[ky]:
if type(itm) == tuple:
add_command(mi, itm)
else:
add_sub_menu(mi, itm)
menuoptions = {'File': [('Save Employee', self.do_nothing),
('Edit Employee', self.do_nothing),
('Delete Employee', self.do_nothing),
('Save All Changes', self.do_nothing)],
'View': [('Employee Management', self.do_nothing),
('Employee Rating', self.do_nothing)],
}
mbar = tk.Menu(frm)
add_sub_menu(mbar, menuoptions)
frm.config(menu=mbar)
return mbar
def select_employee(self, event):
selection = event.widget.curselection()
if self.selected_employee != self.cur_emps[selection[0]]:
self.selected_employee = self.cur_emps[selection[0]]
# if selection:
# index = selection[0]
# data = event.widget.get(index)
def build_list_frame(self, parent):
""" frame to display list of current employees. Always visible as per instructions"""
self.emp_list_frm = tk.Frame(parent, bg='skyblue', relief= tk.RAISED, borderwidth= 5)
self.emp_list_frm.grid(row= 0 , sticky= (tk.E, tk.W))
emp_list_lbl = tk.Label(self.emp_list_frm, text='Current Employees',
bg='systembuttonface', justify= tk.CENTER)
emp_list_lbl.grid(row=0, column=1, sticky= (tk.E, tk.W))
self.cur_emps = list(x for x in sorted(self.emp_list.keys()))
self.emp_list_dsply = tk.Listbox(self.emp_list_frm, width=75,
listvariable =tk.StringVar(value= self.cur_emps) )
self.emp_list_dsply.grid(row=1, columnspan=3)
self.emp_list_dsply.bind("<<ListboxSelect>>", self.select_employee)
To run the above:
emp_file = 'employees.txt'
emplist = load_employees(emp_file)
EmployeeForm(load_employees(emp_file))
Once you select an employee from the listbox selection options, the contents of self.selected_employee will reflect the employee object which then can be referenced by the delete method, and the edit method for further actions.

How can i get the value from the entry and inject into the init function parameter?

Here's the code:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import sys
class TwitterBot:
def __init__(self, username, password):
self.username = username
self.password = password
entry_user = tk.Entry(lower_frame, bg="white", fg='black', bd=0)
#entry_user.insert(0, "Username")
#entry_user.bind("<Button-1>", del_value_user)
entry_user.pack(expand = "yes")
entry_pass = tk.Entry(lower_frame, bg="white", fg='black', bd=0)
#entry_pass.insert(0, "Password")
#entry_pass.bind("<Button-1>", del_value_pass)
entry_pass.pack(expand = "yes")
sasha = TwitterBot(entry_user.get(), entry_pass.get())
The entry never send the values I typed in into sasha = TwitterBot(entry, entry2)
Meaning I want that inside tkinter interface, I type in two entries that supposed to be username and password and when I execute the function those values get injected. I think the problem is that self.username and self.password are defined inside of the __init__ and so if those entries stay empty at the launch so i cant get them to inject. cause I can print my entry.get() values. I just cant make them replace the two first parameters of my __init__ function. Does anybody knows how to help?
Try this:
import tkinter as tk
class TwitterBot:
def __init__(self, username, password):
print("Username =", username, " Password =", password)
self.username = username
self.password = password
def create_bot(event=None):
sasha = TwitterBot(entry_user.get(), entry_pass.get())
print("started bot")
root = tk.Tk()
entry_user = tk.Entry(root, bg="white", fg='black', bd=0)
#entry_user.insert(0, "Username")
#entry_user.bind("<Button-1>", del_value_user)
entry_user.pack(expand=True)
# Log in if the user presses the Enter key:
entry_user.bind("<Return>", create_bot)
entry_pass = tk.Entry(root, bg="white", fg='black', bd=0)
#entry_pass.insert(0, "Password")
#entry_pass.bind("<Button-1>", del_value_pass)
entry_pass.pack(expand=True)
# Log in if the user presses the Enter key:
entry_pass.bind("<Return>", create_bot)
button = tk.Button(root, text="Log in", command=create_bot)
button.pack()
root.mainloop()
Your code wasn't working because as soon as your code created the entries it tried to get the data out of them (which obviously is an empty string) and created the TwitterBot object. To make it work you have to give the user time to enter their details in the entries by adding a button/binding to the user pressing the Enter key.
I created a button and placed it at the bottom of the window. When you click the button it calls create_bot which creates the TwitterBot object.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import sys
import tkinter as tk
from tkinter import *
from tkmacosx import Button as button
class TwitterBot:
def __init__(self, username, password):
print("Username =", username, " Password =", password)
self.username = username
self.password = password
def open_br(self):
self.bot = webdriver.Firefox()
def end_br(self):
self.bot.quit()
def login(self):
bot = self.bot
bot.get("http://twitter.com/login/")
time.sleep(3)
email = bot.find_element_by_name("session[username_or_email]")
password = bot.find_element_by_name("session[password]")
email.clear()
password.clear()
email.send_keys(self.username)
password.send_keys(self.password)
password.send_keys(Keys.RETURN)
time.sleep(3)
def like_tweet(self, hashtag):
bot = self.bot
bot.get('https://twitter.com/search?q='+hashtag+'&src=typed_query')
time.sleep(3)
for i in range(1,8):
bot.execute_script('window.scrollTo(0,document.body.scrollHeight)')
time.sleep(2)
tweets = bot.find_elements_by_class_name('tweet')
tweetLinks = [i.get_attribute('href') for i in bot.find_elements_by_xpath("//a[#dir='auto']")]
filteredTweet = list(filter(lambda x: 'status' in x,tweetLinks))
print(filteredTweet)
for link in filteredTweet:
bot.get(link)
time.sleep(5)
if drop2_var.get() == "Retweet":
try:
bot.find_element_by_xpath("//div[#data-testid='retweet']").click()
bot.find_element_by_xpath("//div[#data-testid='retweetConfirm']").click()
time.sleep(3)
except Exception as ex:
time.sleep(10)
elif drop2_var.get() == "Likes":
bot.find_element_by_xpath("//div[#data-testid='like']").click()
time.sleep(3)
# def create_bot(event=None):
# sasha = TwitterBot(entry_user.get(), entry_pass.get())
# print("started bot")
sasha = TwitterBot("", "")
root = tk.Tk()
HEIGHT = 800
WIDTH = 400
#FUNCTIONS CLEARING ENTRY
def del_value(event): # note that you must include the event as an arg, even if you don't use it.
entry.delete(0, "end")
return None
def del_value_user(event): # note that you must include the event as an arg, even if you don't use it.
entry_user.delete(0, "end")
return None
def del_value_pass(event): # note that you must include the event as an arg, even if you don't use it.
entry_pass.delete(0, "end")
return None
def ex():
root.quit()
#PROGRAM SETTINGS
root.title("Social Bot")
root.minsize(400, 800)
#root.iconbitmap("/Users/sashakharoubi/Desktop/BOOTCAMP/Week 9/Day 2/image/logo.ico")
root.config(background="#66b3ff")
canvas = tk.Canvas(root, height= HEIGHT, width = WIDTH, bd=0, highlightthickness = 0)
canvas.pack()
# background_image = tk.PhotoImage(file = 'blue.png')
# background_label = tk.Label(root, image =background_image)
# background_label.place(x=0, y=0, relwidth=1, relheight=1)
#MAINFRAME
frame = tk.Frame(root, bg="#222f3e")
frame.place(relx = 0, rely = 0, relwidth = 1, relheight = 1)
#SUBPART FRAME
lower_frame = tk.Frame(root, bg="#E9E9E9", bd=0, highlightthickness = 0, relief="sunken")
#DROPDOWN MENU OPTIONS
OPTIONS = [
"Twitter",
"Instagram(not working)"
]
OPTIONS2 = [
"Likes",
"Retweet"
]
entry_txt = tk.Label(lower_frame, text="Welcome to Social Bot\n\nChoose an action to execute", font=("Montserrat", 15), bg="#E9E9E9", fg="black")
entry_txt.pack(expand = "yes")
#DROPDOWN MENU
drop_var = StringVar(lower_frame)
drop_var.set(OPTIONS[0])
drop2_var = StringVar(lower_frame)
drop2_var.set(OPTIONS2[0])
drop = OptionMenu(lower_frame, drop_var, *OPTIONS)
drop.config(fg="black")
drop.pack()
drop2 = OptionMenu(lower_frame, drop2_var, *OPTIONS2)
drop2.config(fg="black")
drop2.pack()
#ENTRIES
entry = tk.Entry(lower_frame, bg="white", fg='black', bd=0)
entry.insert(0, "-->Topic to like or retweet")
entry.bind("<Button-1>", del_value)
entry.pack(expand = "yes")
entry_user = tk.Entry(lower_frame, bg="white", fg='black', bd=0)
entry_user.insert(0, "----Type Your Username---")
entry_user.bind("<Button-1>", del_value_user)
entry_user.pack(expand = "yes")
#entry_user.bind("<Return>", create_bot)
entry_pass = tk.Entry(lower_frame, bg="white", fg='black', bd=0)
entry_pass.insert(0, "----Type Your Password---")
entry_pass.bind("<Button-1>", del_value_pass)
entry_pass.pack(expand = "yes")
#entry_pass.bind("<Return>", create_bot)
#BUTTONS
button_confirm = button(lower_frame, text="Confirm", bg="white", fg="black")
button_confirm.pack(pady=25, side = 'top')
button_open = button(lower_frame, text="Open Browser", bg="white", fg="black", command= sasha.open_br)
button_open.pack(pady=25, side = 'top')
button_log = button(lower_frame, text="LOG IN", bg='#54a0ff', fg="white", command =sasha.login, bd=0, highlightthickness = 0)
button_log.pack(pady=25, side = 'left')
button_launch = button(lower_frame, text="START", bg='#1dd1a1', fg="white", relief="flat", command = lambda: sasha.like_tweet(entry.get()), bd=0, highlightthickness = 0)
button_launch.pack(pady=25, side = 'right')
button_stop = button(lower_frame, text="STOP", bg="#ff6b6b", fg="white", command= sasha.end_br)
button_stop.pack(pady=25, side = 'bottom')
button_exit = button(lower_frame, text="Exit", bg ="white", fg="black", command= ex)
button_exit.pack(side = 'bottom')
lower_frame.place(relx = 0.1, rely = 0.1, relwidth=0.8, relheight=0.8)
#TITLE
label = tk.Label(frame, text="S O C I A L B O T", font=("Montserrat", 25), bg="white", fg="#222f3e")
label.pack(side="top", fill ="both")
root.mainloop()
v1 = browser.find_element_by_xpath("").text
try put .text at last of your code
then you can print or use v1 as a value

Iteration within tkinter Frame

I would like to use a tkinter GUI to iterate through a dictionary (for example) and allow the user to take actions on its values.
For example, my boss might want to iterate through departments and select which employees to fire. The below code works (mostly) for the first department, but I don't understand how to advance to the next department (self.advance below) .
This question is related but just updates values of existing widgets. The number of employees in each department varies, so I can't just update the names, and I also have to allow vertical scrolling.
The iteration occurs within a frame (innerFrame) and the rest of the UI is mostly static. Should I be destroying and recreating that innerFrame, or just all of the widgets inside it? Either way, how can I advance to the next iteration?
# Example data
emp = {'Sales':['Alice','Bryan','Cathy','Dave'],
'Product':['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren'],
'Marketing':['Marvin'],
'Accounting':['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']}
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.advance)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame( self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor='nw', padx=5, pady=20, expand=True)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
def populateUI(self, title, labelList):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
def advance(self):
# -------------> this is what I don't understand how to do <-------------
self.innerFrame.destroy() # this destroys everything!
# how to advance to next iteration?
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.advance()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root)
while emp:
department, employees = emp.popitem()
app.pack(side='top',fill='both',expand=True)
app.populateUI(title = department, labelList = employees)
root.mainloop()
try:
root.destroy()
except tk.TclError:
pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()
Here's a short rework of your code to handle updating the checkboxes on firing employees and switching frames to display the new employees from the department. I didn't handle advancing if all employees have been fired. There's also a small bug, but I'll leave that to you to figure out.
This could be a lot cleaner. I just didn't want to rewrite all of your code....
# Example data
emp = [['Sales', ['Alice','Bryan','Cathy','Dave']],
['Product', ['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren']],
['Marketing', ['Marvin']],
['Accounting', ['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']]]
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.cursor = 0
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.advance)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame(self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor = 'nw', padx=5,pady=5)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
self.populateUI(*self.get_populate_items())
def get_populate_items(self):
return (emp[self.cursor][0], emp[self.cursor][1])
def populateUI(self, title, labelList):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
for child in self.innerFrame.winfo_children():
child.destroy()
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
def advance(self):
if (self.cursor < len(emp) - 1):
self.cursor += 1
else:
self.cursor = 0
self.populateUI(*self.get_populate_items())
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
emp[self.cursor][1].remove(empName)
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.populateUI(*self.get_populate_items())
# self.advance()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root)
root.mainloop()
# while emp:
# department, employees = emp.popitem()
# app.pack(side='top',fill='both',expand=True)
# app.populateUI(title = department, labelList = employees)
# root.mainloop()
# try:
# root.destroy()
# except tk.TclError:
# pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()
The basic pattern is to have a class or a function for each frame. Each of these classes or functions creates a single Frame, and places all of its widgets in that frame.
Then, all you need to do to switch frames is delete the current frame, and call the function or object to create the new frame. It's as simple as that.
Some examples on this site:
Switching between frames in python with functions
Switch between two frames in tkinter
I accepted Pythonista's answer but eventually wound up doing the following:
the UI constructor gets the data as an argument (perhaps better practice than the global data variable)
the UI populator deletes any existing labels first (see accepted answer)
the UI populator then pops a record off (if remaining, otherwise terminate)
the execute button calls the UI populator after doing its other tasks
the skip button just calls the UI populator (thus the advance function could be removed entirely)
This is what I wound up using. As Pythonista said, it's messy, but we all have to start somewhere.
# Example data
emp = {'Sales':['Alice','Bryan','Cathy','Dave'],
'Product':['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren'],
'Marketing':['Marvin'],
'Accounting':['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']}
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root, data):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.data = data
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.populateUI)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame( self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor='nw', padx=5, pady=20, expand=True)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
self.populateUI()
def populateUI(self):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
for child in self.innerFrame.winfo_children():
child.destroy()
try:
title, labelList = self.data.popitem()
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
except KeyError:
messagebox.showinfo("All done", "You've purged all the departments. Good job, boss.")
self.frame.quit()
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.populateUI()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root, data=emp)
app.mainloop()
try:
root.destroy()
except tk.TclError:
pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()

python error run from cmd

For my coursework i am doing a booking system which uses some tree views. The problem is that if ran from cmd when i double click on a row in the tree view it does not populate the boxes below it, however if i run it from the idle it does. Below is my where i have made my class and two defs which are create_GUI(for first part of gui before double click) and double click(makes second part of GUI)
from tkinter import *
import os
import datetime
import sqlite3
from tkinter.ttk import Combobox,Treeview,Scrollbar
import tkinter as tk
import Utilities
class Application(Frame):
""" Binary to Decimal """
def __init__(self, master):
""" Initialize the frame. """
super(Application, self).__init__(master)
self.grid()
self.create_GUI()
def Quit(self):
self.master.destroy()
def create_GUI(self):
frame1 = tk.LabelFrame(root, text="frame1", width=300, height=130, bd=5)
frame2 = tk.LabelFrame(root, text="frame2", width=300, height=130, bd=5)
frame1.grid(row=0, column=0, columnspan=3, padx=8)
frame2.grid(row=1, column=0, columnspan=3, padx=8)
self.title_lbl = Label(frame1, text = "Students")
self.title_lbl.grid(row = 0, column = 2)
self.fn_lbl = Label(frame1, text = "First Name:")
self.fn_lbl.grid(row = 1 , column = 1)
self.fn_txt = Entry(frame1)
self.fn_txt.grid(row = 1, column = 2)
self.ln_lbl =Label(frame1, text = "Last Name:")
self.ln_lbl.grid(row = 2, column = 1)
self.ln_txt = Entry(frame1)
self.ln_txt.grid(row = 2, column = 2)
self.q_btn = Button(frame1, text = "Back",padx=80,pady=10, command = lambda: self.Quit())
self.q_btn.grid(row = 3, column = 0)
self.s_btn = Button(frame1, text = "search",padx=80,pady=10, command = lambda: self.search())
self.s_btn.grid(row = 3,column = 3)
self.tree = Treeview(frame2,height = 6)
self.tree["columns"] = ("StudentID","First Name","Last Name")#,"House Number", "Street Name", "Town Or City Name","PostCode","MobilePhoneNumber")
self.tree.column("StudentID",width = 100)
self.tree.column("First Name",width = 100)
self.tree.column("Last Name", width = 100)
## self.tree.column("House Number", width = 60)
## self.tree.column("Street Name", width = 60)
## self.tree.column("Town Or City Name", width = 60)
## self.tree.column("PostCode", width = 60)
## self.tree.column("MobilePhoneNumber", width = 60)
self.tree.heading("StudentID",text="StudentID")
self.tree.heading("First Name",text="First Name")
self.tree.heading("Last Name",text="Last Name")
## self.tree.heading("House Number",text="House Number")
## self.tree.heading("Street Name",text="Street Name")
## self.tree.heading("Town Or City Name",text="Town Or City Name")
## self.tree.heading("PostCode",text="PostCode")
## self.tree.heading("MobilePhoneNumber",text="MobilePhoneNumber")
self.tree["show"] = "headings"
yscrollbar = Scrollbar(frame2, orient='vertical', command=self.tree.yview)
xscrollbar = Scrollbar(frame2, orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=yscrollbar.set, xscroll=xscrollbar.set)
yscrollbar.grid(row=1, column=5, padx=2, pady=2, sticky=NS)
self.tree.grid(row=1,column=0,columnspan =5, padx=2,pady=2,sticky =NSEW)
self.tree.bind("<Double-1>",lambda event :self.OnDoubleClick(event))
def OnDoubleClick(self, event):
frame3 = tk.LabelFrame(root, text="frame1", width=300, height=130, bd=5)
frame3.grid(row=2, column=0, columnspan=3, padx=8)
self.message=StringVar()
self.message.set("")
self.lblupdate = Label(frame3, textvariable = self.message).grid(row=0,column=0,sticky=W)
curItem = self.tree.focus()
contents =(self.tree.item(curItem))
StudentDetails = contents['values']
print(StudentDetails)
self.tStudentID=StringVar()
self.tFirstName = StringVar()
self.tLastName = StringVar()
self.tHouseNumber = StringVar()
self.tStreetName = StringVar()
self.tTownOrCityName = StringVar()
self.tPostCode = StringVar()
self.tEmail = StringVar()
self.tMobilePhoneNumber = StringVar()
self.tStudentID.set(StudentDetails[0])
self.tFirstName.set(StudentDetails[1])
self.tLastName.set(StudentDetails[2])
self.tHouseNumber.set(StudentDetails[3])
self.tStreetName.set(StudentDetails[4])
self.tTownOrCityName.set(StudentDetails[5])
self.tPostCode.set(StudentDetails[6])
self.tEmail.set(StudentDetails[7])
self.tMobilePhoneNumber.set(StudentDetails[8])
self.inst_lbl0 = Label(frame3, text = "Student ID").grid(row=5,column=0,sticky=W)
self.StudentID = Label(frame3, textvariable=self.tStudentID).grid(row =5,column=1,stick=W)
self.inst_lbl1 = Label(frame3, text = "First Name").grid(row=6,column=0,sticky=W)
self.NFirstName = Entry(frame3, textvariable=self.tFirstName).grid(row =6,column=1,stick=W)
self.inst_lbl2 = Label(frame3, text = "Last Name").grid(row=7,column=0,sticky=W)
self.NLastName = Entry(frame3, textvariable=self.tLastName).grid(row =7,column=1,stick=W)
self.inst_lbl3 = Label(frame3, text = "House Number").grid(row=8,column=0,sticky=W)
self.HouseNumber = Entry(frame3,textvariable=self.tHouseNumber).grid(row=8,column=1,sticky=W)
self.inst_lbl4 = Label(frame3, text = "Street Name").grid(row=9,column=0,sticky=W)
self.StreetName =Entry(frame3,textvariable=self.tStreetName).grid(row=9,column=1,sticky=W)
self.inst_lbl5 = Label(frame3, text = "Town or City Name").grid(row=10,column=0,sticky=W)
self.TownOrCityName =Entry(frame3,textvariable=self.tTownOrCityName).grid(row=10,column=1,sticky=W)
self.inst_lbl6 = Label(frame3, text = "Postcode").grid(row=11,column=0,sticky=W)
self.PostCode = Entry(frame3,textvariable=self.tPostCode).grid(row=11,column=1,sticky=W)
self.inst_lbl7 = Label(frame3, text = "Email").grid(row=12,column=0,sticky=W)
self.Email =Entry(frame3,textvariable=self.tEmail).grid(row=12,column=1,sticky=W)
self.inst_lbl8 = Label(frame3, text = "Mobile phonenumber").grid(row=13,column=0,sticky=W)
self.MobilePhoneNumber =Entry(frame3,textvariable=self.tMobilePhoneNumber).grid(row=13,column=1,sticky=W)
self.btnSaveChanges = Button(frame3, text = "save changes",padx=80,pady=10,command = lambda:self.SaveChanges()).grid(row=14,column=0,sticky=W)
self.btnSaveChanges = Button(frame3, text = "delete record",padx=80,pady=10,command = lambda:self.DeleteRecord()).grid(row=14,column=1,sticky=W)
def search(self):
FirstName = self.fn_txt.get()
LastName = self.ln_txt.get()
with sqlite3.connect("GuitarLessons.db") as db:
cursor = db.cursor()
cursor.row_factory = sqlite3.Row
sql = "select StudentID,FirstName,LastName,HouseNumber,StreetName,TownOrCityName,PostCode,Email,MobilePhoneNumber"\
" from tblStudents"\
" where FirstName like ?"\
" and LastName like ?"
cursor.execute(sql,("%"+FirstName+"%","%"+LastName+"%",))
StudentList = cursor.fetchall()
print(StudentList)
self.loadStudents(StudentList)
def loadStudents(self,StudentList):
for i in self.tree.get_children():
self.tree.delete(i)
for student in StudentList:
self.tree.insert("" , 0,values=(student[0],student[1],student[2],student[3],student[4],student[5],student[6],student[7],student[8]))
def SaveChanges(self):
valid = True
self.message.set("")
NFirstName = self.tFirstName.get()
NLastName = self.tLastName.get()
NHouseNumber = self.tHouseNumber.get()
NStreetName = self.tStreetName.get()
NTownOrCityName = self.tTownOrCityName.get()
NPostCode = self.tPostCode.get()
NEmail = self.tEmail.get()
NMobilePhoneNumber = self.tMobilePhoneNumber.get()
StudentID = self.tStudentID.get()
if NFirstName == "" or NLastName == "" or NEmail == "" or NMobilePhoneNumber == "":
valid = False
self.message.set('missing details,first name,last name,phone number, email are all needed')
if not Utilities.is_phone_number(NMobilePhoneNumber ):
valid = False
self.message.set('invalid mobile phone number')
if not Utilities.is_postcode(NPostCode):
valid = False
self.message.set('invalid postcode')
if not Utilities.is_email(NEmail):
valid = False
self.message.set('invalid email')
if NHouseNumber != "":
if int(NHouseNumber) < 0:
self.message.set('invalid house number')
if valid == True:
with sqlite3.connect("GuitarLessons.db") as db:
cursor = db.cursor()
sql = "update tblStudents set FirstName =?,LastName=?,HouseNumber=?,StreetName=?,TownOrCityName=?,PostCode=?,Email=?,MobilePhoneNumber=? where StudentID=?"
cursor.execute(sql,(NFirstName,NLastName,NHouseNumber,NStreetName,NTownOrCityName,NPostCode,NEmail,NMobilePhoneNumber,StudentID))
db.commit()
self.message.set("student details updated")
def DeleteRecord(self):
StudentID = self.tStudentID.get()
#StudentID = int(StudentID)
with sqlite3.connect("GuitarLessons.db") as db:
cursor = db.cursor()
sql = "delete from tblStudents where StudentID = ?"
cursor.execute(sql,(StudentID))
db.commit()
self.tlabeupdate.set("student details deleted")
root = Tk()
root.title("booking system")
root.geometry("800x800")
root.configure(bg="white")
app = Application(root)
root.mainloop()
EDIT
when i was copyign and pasting the rest of my code that i forgot to put in the original post i found that it only stops working if i open it through the student menu(separate peice of code) but it works if i dont go through the menu
You must call mainloop() on the root window so that your program can process events.
You create LabelFrames in the parent called root, but root does not exist. To correct it pass master to the function, which receives it as root
class Application():
""" Binary to Decimal """
def __init__(self, master):
""" Initialize the frame. """
self.create_GUI(master)
def create_GUI(self, root):
frame1 = tk.LabelFrame(root, text="frame1", width=300, height=130, bd=5)

Categories