I have a Python program that gets information from a database; in this case, we're making hotel reservations. My issue is that if I use checkboxes and select multiple rooms--only the first in the list shows up. I believe the error to be a counting error of sorts that resides in my checkDetails method.
It would appear, then when trying to get the value of the checkbox, it only works for the first checkbox in the list. To be perfectly honest, I'm not 100% sure how to describe the issue. In lieu of words, I've uploaded four gifs showing the issue.
GOOD: Selecting the first two works fine. Selecting the first item alone works as well. No matter what, the first item always works.
BAD_1:Selecting the first item and another item (any item except the second) only displays the first item regardless.
BAD_2:Selecting any two items that don't involve the first item, results in neither item being displayed.
BAD_3:Selecting any single item that isn't the first item results in it not being displayed.
##(USER)MAKE NEW RESERVATION##
def searchReservation(self):
self.root = tk.Tk()
self.root.title("Search Rooms")
# city option button
self.cityvariable = StringVar(self.root)
self.cityvariable.set("Select City")
w = OptionMenu(self.root, self.cityvariable, "Atlanta", "Charlotte",
"Savannah", "Orlando", "Miami").grid(row=0, column=0)
# start and end labels
self.startDate = tk.Label(
self.root, text="Start Date (YYYY-MM-DD)") .grid(row=1, column=0)
self.endDate = tk.Label(
self.root, text="End Date (YYYY-MM-DD)").grid(row=1, column=1)
# start and end entries
self.startStringEntry = tk.Entry(self.root, state=NORMAL, width=10)
self.startStringEntry.grid(row=2, column=0)
self.startStringEntry.insert(0, '2015-11-23') #TODO debugging--remove
self.endStringEntry = tk.Entry(self.root, state=NORMAL, width=10)
self.endStringEntry.grid(row=2, column=1)
self.endStringEntry.insert(0, '2015-11-25') #TODO debugging--remove
# search button
self.search_button = tk.Button(
self.root, text="Search Availabilities", command=self.makeReservation)
self.search_button.grid()
self.root.mainloop()
def validDate(self, date):
correctdate = None
try:
startdate = datetime.datetime.strptime(date, "%Y-%m-%d")
correctdate = True
except ValueError:
correctdate = False
if correctdate is False:
messagebox.showerror(
title="Warning", message="A valid date format is required.")
return correctdate
def makeReservation(self):
if self.startStringEntry.get() == self.endStringEntry.get():
messagebox.showerror(
title="Warning", message="Reservation must be at least a day")
elif not self.validDate(self.startStringEntry.get()) or not self.validDate(self.endStringEntry.get()):
return
elif datetime.datetime.strptime(self.startStringEntry.get(), '%Y-%m-%d') > datetime.datetime.strptime(self.endStringEntry.get(), '%Y-%m-%d'):
messagebox.showerror(
title="Warning", message="End date must be after start date")
else:
self.search_button.config(state='disabled')
self.root.withdraw()
self.makeRes = tk.Tk()
self.makeRes.title("Make a Reservation")
# date labels
Label(self.makeRes, text="Start Date") .grid(row=0, column=0)
Label(self.makeRes, text="End Date").grid(row=0, column=1)
Label(self.makeRes, text=self.startStringEntry.get()).grid(
row=1, column=0)
Label(self.makeRes, text=self.endStringEntry.get()).grid(
row=1, column=1)
Label(self.makeRes, text='City').grid(row=0, column=2)
Label(self.makeRes, text=self.cityvariable.get()).grid(
row=1, column=2)
# column headers
roomnumber = tk.Label(
self.makeRes, text="Room Number").grid(row=2, column=0)
roomcat = tk.Label(self.makeRes, text="Room Category").grid(
row=2, column=1)
capacity = tk.Label(
self.makeRes, text="Room Capacity").grid(row=2, column=2)
costperday = tk.Label(
self.makeRes, text="Cost Per Day").grid(row=2, column=3)
costextra = tk.Label(
self.makeRes, text="Extra Bed Cost").grid(row=2, column=4)
availability = tk.Label(
self.makeRes, text="Select Room").grid(row=2, column=5)
# insert available rooms
sql = """SELECT a.RoomNum, a.Category, b.RoomCapacity, a.CostPerDay, a.ExtraBedCost
FROM ROOM a, ROOM_CAPACITY b
WHERE a.Category = b.Category
AND a.RoomLocation = '""" + self.cityvariable.get() + """'
AND (
a.RoomNum, a.RoomLocation
) NOT
IN (
SELECT DISTINCT c.RoomNum, c.Location
FROM ROOM_RESERVATION c, RESERVATION d
WHERE c.ReservationID = d.ReservationID
AND c.Location = a.RoomLocation
AND d.RefundAmount IS NULL
AND """ + self.endStringEntry.get() + """ <= d.EndDate
AND """ + self.startStringEntry.get() + """ >= d.StartDate
)"""
cursor.execute(sql)
self.count = 3
self.data = []
for data in cursor:
self.data.append(data)
for i in range(5):
Label(self.makeRes, text=data[i]).grid(
row=self.count, column=i)
self.count = self.count + 1
if self.count == 3:
messagebox.showerror(
title="Warning", message="No rooms available for city and dates")
self.makeRes.destroy()
self.searchReservation()
else:
# making checkboxes to select room
self.vars = []
for rowNum in range(3, self.count):
self.var = IntVar(self.makeRes)
Checkbutton(self.makeRes, variable=self.var).grid(
row=rowNum, column=5)
self.vars.append(self.var)
self.check_detail_button = Button(
self.makeRes, text='Check Details', command=self.checkDetails)
self.check_detail_button.grid(row=self.count + 1, column=5)
def checkDetails(self):
noneselected = True
for i in self.vars:
if i.get() == 1:
noneselected = False
break
if noneselected is True:
messagebox.showerror(title="Warning", message="No rooms selected")
else:
self.check_detail_button.config(state='disabled')
ttk.Separator(self.makeRes, orient=HORIZONTAL).grid(
column=0, row=self.count+2, columnspan=10, sticky=(W, E))
# column headers
Label(self.makeRes, text="Room Number").grid(
row=self.count + 3, column=0)
Label(self.makeRes, text="Room Category").grid(
row=self.count + 3, column=1)
Label(self.makeRes, text="Room Capacity").grid(
row=self.count + 3, column=2)
Label(self.makeRes, text="Cost Per Day").grid(
row=self.count + 3, column=3)
Label(self.makeRes, text="Extra Bed Cost").grid(
row=self.count + 3, column=4)
Label(self.makeRes, text="Select Extra Bed").grid(
row=self.count + 3, column=5)
self.count += 4
new_count = 0
for data in self.data:
print(data, self.vars[new_count].get()) #TODO remove
if self.vars[new_count].get() == 1:
for i in range(5):
Label(self.makeRes, text=data[i]).grid(
row=self.count + new_count, column=i)
new_count += 1
# making checkboxes to select beds
self.beds = []
count = 0
for rowNum in range(self.count, self.count + new_count):
if self.vars[count].get() == 1:
var = IntVar(self.makeRes)
checkBox = tk.Checkbutton(
self.makeRes, variable=var).grid(row=rowNum, column=5)
self.beds.append(var)
count += 1
self.count += new_count
Label(self.makeRes, text='Total Cost').grid(
row=self.count + 1, column=2)
# CALCULATE TOTAL COSTS
total_cost = 0
count = 0
self.new_data = []
for i in self.data:
if self.vars[count].get() == 1:
total_cost += i[3]
self.new_data.append(i)
count += 1
val = str(total_cost)
self.total_costs_entry = Entry(self.makeRes)
self.total_costs_entry.grid(row=self.count + 1, column=3)
self.total_costs_entry.insert(0, val)
self.total_costs_entry.config(state='readonly')
Button(self.makeRes, text='Update total', command=self.updateTotalCosts).grid(
row=self.count + 1, column=4)
Label(self.makeRes, text='Use Card').grid(
row=self.count + 2, column=2)
cursor.execute(
'SELECT CardNum FROM PAYMENT_INFO WHERE Username="' + self.user + '"')
cards = ['-']
for i in cursor:
cards.append(i)
self.card = StringVar(self.makeRes)
self.opts = OptionMenu(self.makeRes, self.card, *cards)
self.opts.grid(row=self.count + 2, column=3)
Button(self.makeRes, text="Add Card", command=self.addCreditCard).grid(
row=self.count + 2, column=4)
Button(self.makeRes, text="Delete Card", command=self.deleteCard).grid(
row=self.count + 2, column=5)
Button(self.makeRes, text='Submit', command=self.submitReservation).grid(
row=self.count + 3, column=5)
def updateTotalCosts(self):
total_cost = 0
count = 0
self.new_data = []
for i in self.data:
if self.vars[count].get() == 1:
total_cost += i[3]
self.new_data.append(i)
count += 1
count = 0
for i in self.new_data:
if self.beds[count].get() == 1:
total_cost += i[4]
count += 1
cursor.execute("SELECT DATEDIFF(%s, %s)",
(self.endStringEntry.get(), self.startStringEntry.get()))
diff = cursor.fetchone()
diff = diff[0]
total_cost = diff * total_cost
self.total_costs_entry.destroy()
self.total_costs_entry = Entry(self.makeRes)
self.total_costs_entry.grid(row=self.count + 1, column=3)
self.total_costs_entry.insert(0, str(total_cost))
self.total_costs_entry.config(state='readonly')
EDIT: Why not just do this?
for data in self.data:
print(data, self.vars[new_count].get()) #TODO debugging--remove
if self.vars[new_count].get() == 1:
for i in range(5):
Label(self.makeRes, text=data[i]).grid(
row=self.count + new_count, column=i)
new_count += 1
Definitely one problem is that you're creating more than one instance of tk.Tk(). Tkinter isn't designed to work that way, and it will yield problems similar to what you're seeing.
If you need additional windows, you must create instances of tk.Toplevel.
Another problem is this loop:
for data in self.data:
if self.vars[new_count].get() == 1:
for i in range(5):
Label(self.makeRes, text=data[i]).grid(
row=self.count + new_count, column=i)
new_count += 1
There is a fundamental flaw in the logic. Even though you loop over the data, you keep checking self.vars[new_count]. So, even though you eventually land on data item 3, 4, 5, etc, you keep checking self.vars[0] over and over and over. Once you find one checked item, you now keep looking at self.vars[1] even though you may now be on data item number 3, 4, 5, etc.
One simple fix is to make sure you're iterating over the variables the same as you are iterating over the data values:
for var, data in zip(self.vars, self.data):
if var.get() == 1:
for i in range(5):
Label(self.makeRes, text=str(data[i]) + "?").grid(
row=self.count + new_count, column=i)
new_count += 1
The above assumes there is a 1:1 relationship between the items in self.vars and the items in self.data. It's hard to tell if that's a valid assumption or not.
Related
sorry for the constant pings but got to finish this project by Monday and its gone absolutely horribly! For this section of the code, when the employee details have been inputted, I want the system to search the employee list file for any existing employees with the same ID. If there is, I want the system to ask the employee if they want to create a new employee regardless and if they click the confirm button, the employee will be created with a different ID. If no employee has been found which has the same ID then a new employee will automatically be created.
The problem is that even when an employee is detected, it will first run through the expected code, but will then run through the code designated for when an employee is not detected.
def add_emp():
empSurname = txtSurnameS.get()
empForename = txtForenameS.get()
empPhone = txtPhoneS.get()
empGender = comboGenderS.get()
empDOB = txtDOBS.get()
empEmail = txtEmailS.get()
empHouseNum = txtHouseNumS.get()
empStreetName = txtStreetNameS.get()
empTC = txtTcS.get()
empCounty = txtCountyS.get()
empPostcode = txtPostcodeS.get()
empPassword = txtPasswordS.get()
txtSurnameS.delete(0,END)
txtForenameS.delete(0,END)
txtPhoneS.delete(0,END)
comboGenderS.delete(0,END)
txtDOBS.delete(0,END)
txtEmailS.delete(0,END)
txtHouseNumS.delete(0,END)
txtStreetNameS.delete(0,END)
txtTcS.delete(0,END)
txtCountyS.delete(0,END)
txtPostcodeS.delete(0,END)
txtPasswordS.delete(0,END)
CAPL = empSurname.upper()
CAPF = empForename.upper()
with open("employees.txt", "r") as empList:
for i in empList:
fields = i.split(", ")
if len(fields) < 2:
continue
oldID = fields[0]
if oldID[:4] == CAPL[:3]+CAPF[:1]:
exEmp = "Employee with name", empForename, " ", empSurname, "already exists, do you still wish to create account?"
lblConfirm=Label(login_frame3,text=exEmp,font=("Calibri", 16), bg="white", fg="black", width = 135, height = 5)
lblConfirm.grid(row=8, column=1, columnspan = 8, rowspan = 2)
def confirm():
for i in employeeList:
counts=1
if i[:4] == CAPL[:3] + CAPF[:1]:
counts = counts + 1
empIDs = CAPL[:3] + CAPF[:1] + str("{:02d}".format(counts))
empList.close()
newEmp = classFunctions.Employee(empIDs, empSurname, empForename, empGender, empPhone, empDOB, empEmail, empHouseNum, empStreetName, empPostcode, empTC, empCounty, empPassword)
btnConfirm=Button(login_frame3,command=confirm,text="Confirm", width=15, font=("Calibri", 16, "bold"), fg="white", bg="black")
btnConfirm.grid(row=11, column=1)
else:
CAPL = empSurname.upper()
CAPF = empForename.upper()
employeeList = open("employees.txt", "r")
count = 1stack
for i in employeeList:
if i[:4] == CAPL[:3] + CAPF[:1]:
count = count + 1
empIDs = CAPL[:3] + CAPF[:1] + str("{:02d}".format(count))
newEmp = classFunctions.Employee(empIDs, empSurname, empForename, empGender, empPhone, empDOB, empEmail, empHouseNum, empStreetName, empPostcode, empTC, empCounty, empPassword)
empList.close()
show_frame(login_frame)
addBtn=Button(login_frame3,command=add_emp,text="Add Emp", width=15, font=("Calibri", 16, "bold"), fg="white", bg="black")
addBtn.grid(row=7, column=1)
btnClose=Button(login_frame3,command=lambda:show_frame(login_frame),text="Cancel", width=15, font=("Calibri", 16, "bold"), fg="white", bg="black")
btnClose.grid(row=7, column=2)
This problem did not occur until I added the confirm subroutine in. Any help would be appreciated!
I just start learning tkinter python for knapsack program. When I try to calculate, it doesn't do anything. And I am getting this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/init.py", line 1921, in call
return self.func(*args)
TypeError: knapSack() missing 3 required positional arguments: 'W', 'wt', and 'val'
My code looks like this
import tkinter as tk
window = tk.Tk()
window.title("0/1 Knapsack")
canvas = tk.Canvas(window, height=1000, width=1000, bg = "#ADD8E6")
canvas.pack()
frame = tk.Frame(window, bg="white")
frame.place(relwidth=0.8, relheight=0.8,relx=0.1,rely=0.1)
def on_submit():
num_entries = int(num_entries_entry.get())
for i in range(num_entries):
Title_label = tk.Label(frame, text = "Items information")
Title_label.grid(row=5, column=1)
Title_label.config(font=("Arial", 18))
entry = tk.Entry(frame)
entry_label = tk.Label(frame, text = " Weight of items : " )
entry_label.grid(row=6,column=0)
entry.grid(row=7+i, column=0)
entry2 = tk.Entry(frame)
entry2_label = tk.Label(frame, text = " Value of each items")
entry2_label.grid(row=6, column=1)
entry2.grid(row=7+i, column=1)
capacity_label = tk.Label(frame, text =" Please select the capacity of your bag :")
capacity_spinbox = tk.Spinbox(frame, from_=1, to=100 )
capacity_label.grid(row=6, column=2)
capacity_spinbox.grid(row=7,column=2)
calculate_button =tk.Button(frame,text="Calculate", command = knapSack)
calculate_button.grid(row=7,column=3)
def calculate(weights, values, capacity):
result = knapSack(capacity, weights, values)
# Create a label to display the result
result_label = tk.Label(frame, text="Result: " + str(result))
result_label.grid(row=14, column=0)
def print_value_table(table):
print("Value Table:")
for row in table:
print(row)
def print_keep_table(table):
print("Keep Table:")
for row in table:
print(row)
def knapSack(W, wt, val):
n=len(val)
value_table = [[0 for x in range(W + 1)] for x in range(n + 1)]
keep_table = [[0 for x in range (W+1)] for x in range (n+1)]
for i in range(n + 1):
for j in range(W + 1):
if i == 0 or j == 0:
value_table[i][j] = 0
keep_table[i][j] = 0
elif wt[i-1] <= j:
if(val[i-1] + value_table[i-1][j-wt[i-1]]) > value_table[i-1][j]:
value_table[i][j] = val [i-1]+ value_table[i-1][j-wt[i-1]]
keep_table [i][j] = 1
else:
value_table[i][j] = value_table[i-1][j]
keep_table[i][j] = 0
else:
value_table[i][j] = value_table[i-1][j]
keep_table[i][j] = 0
print_value_table(value_table)
print_keep_table(keep_table)
return value_table[n][W]
num_entries_label = tk.Label(frame, text="Enter the number of items:")
num_entries_label.grid(row=1, column=1)
num_entries_entry = tk.Entry(frame)
num_entries_entry.grid(row=2, column=1)
next_button = tk.Button(frame, text="Next", command=on_submit)
next_button.grid(row=3, column=1)
title_label = tk.Label(frame, text = "Hi! Please follow the instructions!")
title_label.config(font=("Arial", 18))
window.mainloop()
Below is the code for a smaller version of a project I am working on. Basically when I try to delete one of the entries, the delete function works, but only once. After that it starts duplicating the entries I have deleted until giving me the IndexError: list assignment index out of range
from tkinter import *
gui = Tk()
details_list = []
counters = {'total_entires':0, 'entries_count':0}
error_print = Label(gui)
name_entry = Entry(gui)
name_entry.grid(column=1, row=0, sticky=W)
delete_row_entry = Entry(gui, width=5)
delete_row_entry.grid(column=4,row=3, sticky=W, pady=(2,0))
def print_entries():
global details_list, row_display, name_display
line_no = ""
for x in range(len(details_list)):
line_no = str(x + 1)
row_display = Label(gui, text=line_no)
row_display.grid(column=0, row=x+2)
name_display = Label(gui, text=(details_list[x][0]))
name_display.grid(column=1, row=x+2)
def delete_row():
global details_list, row_display
del details_list[int(delete_row_entry.get()) - 1]
entries_count = counters['entries_count']
counters['total_entires'] -= 1
delete_row_entry.delete(0,'end')
row_display.destroy()
name_display.destroy()
print_entries()
def append_name():
details_list.append([name_entry.get()])
counters['total_entires'] += 1
def labels():
Label(gui, text='Row').grid(column=0, row=1, sticky=W, padx=(0,5))
Label(gui, text='Name').grid(column=1, row=1, sticky=W, padx=5)
def buttons():
Button(gui, text='Quit', command=quit, width=15).grid(column=4, row=0, sticky=W)
Button(gui, text='Append Details', command=append_name, width=15).grid(column=4, row=1,
sticky=W)
Button(gui, text='Print Details', command=print_entries, width=15).grid(column=4, row=2,
sticky=W)
Button(gui, text='Delete Row', command=delete_row, width=10).grid(column=4, row=3,
sticky=E)
def main():
labels()
buttons()
gui.mainloop()
main()
There are two issues in your code:
you have created new set of labels whenever print_entries() is executed
the two .destroy() lines just destroy the labels in the last row of the set of labels created inside print_entries()
To fix the issues:
create a list to store those labels created inside print_entries()
delete existing labels before populating new labels inside print_entries()
Below are the modified print_entries() and delete_row() functions:
...
# create a list to store those labels
label_list = []
def print_entries():
# clear current table
for w in label_list:
w.destroy()
label_list.clear()
# show the new table
for x in range(len(details_list)):
row_display = Label(gui, text=x+1)
row_display.grid(column=0, row=x+2)
name_display = Label(gui, text=details_list[x][0])
name_display.grid(column=1, row=x+2)
# store the labels in the list
label_list.extend([row_display, name_display])
def delete_row():
try:
size = len(details_list)
idx = int(delete_row_entry.get()) - 1 # may raise exception
if size and 0 <= idx < size:
del details_list[idx]
# below line seems useless
#entries_count = counters['entries_count']
counters['total_entires'] -= 1
delete_row_entry.delete(0, 'end')
print_entries()
else:
print('row number is out of range' if size else 'empty list')
except ValueError as ex:
print(ex)
...
I have two issues.
One:
I can't figure out how to calculate days left until a specific date which the user inputs in a calendar interface.
Secondly:
I want to use the numbers that the user has input in the interface to do some calculations with, and to watch what is going on I print some of the input to the terminal - however, the .value attribute returns "0" and I don't understand why.
Below the #PROXIMITY comment in the code you will find the calendar/date. I just want to subtract the date today from the date specified by the user in the calendar interface and output the days left.
Below the #VALUE is the calculation that prints "0" when i print the .value attribute.
Full code:
from tkcalendar import * # Calendar module
import tkinter.messagebox # Import the messagebox module
import datetime
import pickle
task_list = []
task_types = ['Sparetime', 'School', 'Work']
class Task:
def __init__(self, n, type_, i, m, p, h, v): #(w=8, p, u, n, v):
self.name = n
self.type = type_
self.impact = i
self.manageability = m
self.proximity = p
self.hours = h
self.value = v
#self.connectivity = c
##self.work = w ##hours of work per day
##self.urgency = u
##self.note = n
##self.value = v
def show_tasks():
# DELETED: for task in task_list:
# REPLACED WITH: task = task_list[-1]
task = task_list[-1]
#print(
#'Task:'+task.name + '\n' +
#'Impact:' + task.impact + '\n' +
#'Manageability:' + task.manageability + '\n' +
#'Hours:' + task.hours + '\n'
#'Value:' + task.value +'\n'
#)
print('Task:')
print(task.name)
print('\n')
print('Impact:')
print(task.impact)
print('\n')
print('manageability:')
print(task.manageability)
print('\n')
print('Hours')
print(task.hours)
print('\n')
print('Value:')
print(task.value)
def open_add_task():
taskwin = Toplevel(root)
taskwin.focus_force()
#TITLE
titlelabel = Label(taskwin, text='Title task concisely:', font=('Roboto',11,'bold')).grid(column=1, row=0)
name_entry = Entry(taskwin, width=40, justify='center')
name_entry.grid(column=1, row=1)
#TYPE
typelabel = Label(taskwin, text='Type', font=('Roboto',10)).grid(column=0, row=2)
type_var = StringVar(value=task_types[0])
OptionMenu(taskwin, type_var, *task_types).grid(column=0, row=3, sticky='nsew')
#IMPACT
impactlabel = Label(taskwin, text='Impact', font=('Roboto',10)).grid(column=1, row=2)
imp_var = StringVar(value=0)
OptionMenu(taskwin, imp_var, *range(0, 10+1)).grid(column=1, row=3, sticky='ns')
#MANAGEABILITY
manlabel = Label(taskwin, text='Manageability', font=('Roboto',10)).grid(column=2, row=2)
man_var = StringVar(value=0)
OptionMenu(taskwin, man_var, *range(0, 10+1)).grid(column=2, row=3, sticky='nsew')
#PROXIMITY
proximity_label = Label(taskwin, text = 'Choose a deadline', font=('Roboto',10), justify='center')
proximity_label.grid(column=1, row=4)
cal = Calendar(taskwin, selectmode='day', year=2021, month=4, day=27)
cal.grid(column=1, row=5)
def get_date():
proximity_output_date.config(text=cal.get_date()) ##the .config didn't work until i did .grid(column=, row=) on seperate lines
#HOURS(required)
hourlabel = Label(taskwin, text='Whole hours \n required', font=('Roboto',10)).grid(column=1, row=16)
hour_entry = Entry(taskwin, width=4, justify='center')
hour_entry.grid(column=1, row=17)
#CONNECTIVITY
#for index, task in enumerate(task_list):
#Checkbutton(taskwin, **options).grid(column=0, row=index)
C_lab = Label(taskwin,text="Check tasks this task is related to").grid(column=1, row=18)
placement=19
for task in task_list:
Checkbutton(taskwin, text=(task.name)).grid(column=1, row=placement, sticky="w")
placement+=1
#VALUE
val_var = (int(imp_var.get()))+ (int(man_var.get()))
def add_task():
if name_entry.get() != '': # If textbox inputfield is NOT empty do this:
task_list.append(Task(name_entry.get(), type_var.get(), imp_var.get(), man_var.get(), cal.get_date(), hour_entry.get(), val_var))
show_tasks()
listbox_tasks.insert(tkinter.END, name_entry.get())
name_entry.delete(0, tkinter.END)
taskwin.destroy()
else:
tkinter.messagebox.showwarning(title='Whoops', message='You must enter a task')
next_button = Button(taskwin, text='Next', font=('Roboto',10), command=add_task).grid(column=2, row=placement, sticky="e")
placement+=1
def sort_tasks():
pass
def delete_task():
try:
task_index = listbox_tasks.curselection()[0]
listbox_tasks.delete(task_index)
except:
tkinter.messagebox.showwarning(title='Error', message='You must select a task to delete')
def save_tasks():
pass
#tasks = listbox_tasks.get(0, listbox_tasks.size())
#pickle.dump(tasks, open('tasks.dat', 'wb'))
root = Tk()
task_frame = Frame()
# Create UI
your_tasks_label = Label(root, text='THESE ARE YOUR TASKS:', font=('Roboto',10, 'bold'), justify='center')
your_tasks_label.pack()
scrollbar_tasks = tkinter.Scrollbar(root)
scrollbar_tasks.pack(side=tkinter.RIGHT, fill=tkinter.Y)
listbox_tasks = tkinter.Listbox(root, height=10, width=50, font=('Roboto',10), justify='center') # tkinter.Listbox(where it should go, height=x, width=xx)
listbox_tasks.pack()
listbox_tasks.config(yscrollcommand=scrollbar_tasks.set)
scrollbar_tasks.config(command=listbox_tasks.yview)
try:
#tasks = pickle.load(open('tasks.dat', 'rb'))
listbox_tasks.delete(0, tkinter.END)
for task in task_list:
listbox_tasks.insert(tkinter.END, task)
except:
tkinter.messagebox.showwarning(title='Phew', message='You have no tasks')
#BUTTONS
Add_Button = Button(root, text='Add New', width=42, command=open_add_task)
Add_Button.pack()
button_delete_task = Button(root, text='Delete task', width=42, command=delete_task)
button_delete_task.pack()
button_save_tasks = Button(root, text='Save tasks', width=42, command=save_tasks)
button_save_tasks.pack()
#sort_type = StringVar(value='All')
#OptionMenu(btn_frame, sort_type, 'All', *task_types).grid(column=0, row=0, sticky='nsew')
#sort_imp = StringVar(value='Any')
#OptionMenu(btn_frame, sort_imp,'Any', *range(0, 10+1)).grid(column=1, row=0, sticky='nsew')
#Button(btn_frame, text='Sort', command=sort_tasks).grid(column=1, row=1, sticky='nsew')
root.mainloop()
how to calculate days left until a specific date
You might subtract datetime.date from datetime.date to get datetime.timedelta object holding numbers of days, consider following example
import datetime
d1 = datetime.date(2021, 1, 1) # year, month, day
d2 = datetime.date(2021, 1, 10)
diff21 = (d2-d1).days
diff12 = (d1-d2).days
print(diff21)
print(diff12)
output
9
-9
For getting current date you might use datetime.date.today().
For your first issue, you can use cal.selection_get() to return the selected date in datetime.date type. Then you can calculate the days left easily:
selected = cal.selection_get()
delta = (selected - datetime.date.today()).days
status = "overdue" if delta <= 0 else f"{delta} days left"
print(f"{selected} ({status})")
For second issue, you need to move the line val_var = (int(imp_var.get()))+ (int(man_var.get())) into add_task() function:
def add_task():
if name_entry.get() != '':
val_var = int(imp_var.get()) + int(man_var.get())
...
else:
...
Note that you need to do some validations on the values returned by imp_var.get() and man_var.get() to avoid exception due to invalid values.
I work on a program that calculates the macros of each meal. You can enter a value in gram and it calculates for each aliment your intake. I would like now to add these values together when I push multiple buttons. Then I'll display the value somewhere and maybe I could do a graph after.
Here I show what my program looks like :
import tkinter as tk
def value_kiwi():
value = ent_quantity.get()
formula = (float(value)/100)
cal = 53
pro = 1.6
glu = 11.1
li = 0.3
Calories = (cal) * formula
Protéines = (pro) * formula
Glucides = (glu) * formula
Lipides = (li) * formula
lbl_cal["text"] =f"{Calories}"
lbl_prot["text"] = f"{Protéines}"
lbl_glu["text"] = f"{Glucides}"
lbl_lip["text"] = f"{Lipides}"
def value_banane():
value = ent_quantity.get()
formula = (float(value)/100)
cal = 90
pro = 1.5
glu = 20.1
li = 0
Calories = (cal) * formula
Protéines = (pro) * formula
Glucides = (glu) * formula
Lipides = (li) * formula
lbl_cal["text"] =f"{Calories}"
lbl_prot["text"] = f"{Protéines}"
lbl_glu["text"] = f"{Glucides}"
lbl_lip["text"] = f"{Lipides}"
window = tk.Tk()
window.title("Calculateur de Calories et Nutriments")
frm_entry = tk.Frame(master=window)
ent_quantity = tk.Entry(master=frm_entry, width=5)
ent_quantity.grid(row=1, column=0,)
lbl_cal = tk.Label(master=window)
lbl_cal.grid(row=1, column=1,)
lbl_prot = tk.Label(master=window)
lbl_prot.grid(row=1, column=2)
lbl_glu = tk.Label(master=window)
lbl_glu.grid(row=1, column=3)
lbl_lip = tk.Label(master=window)
lbl_lip.grid(row=1, column=4)
btn_kiwi = tk.Button(
master=window,
text="Kiwi",
command=value_kiwi,
)
btn_banane = tk.Button(
master=window,
text="Banane",
command=value_banane,
)
lbl_calories = tk.Label(master=window, text="Calories",)
lbl_proteines = tk.Label(master=window, text="Protéines")
lbl_glucides = tk.Label(master=window, text="Glucides")
lbl_lipides = tk.Label(master=window, text="Lipides")
lbl_fruits = tk.Label(master=window, text="Fruits")
frm_entry.grid(row=1, column=0, padx=10)
lbl_calories.grid(row=0,column=1, padx=5, sticky="w")
lbl_proteines.grid(row=0, column=2, padx=10)
lbl_glucides.grid(row=0, column=3, padx=10)
lbl_lipides.grid(row=0,column =4, padx=10)
lbl_fruits.grid(row=1,column =5, padx=10)
btn_kiwi.grid(row=2, column=5, pady=10)
btn_banane.grid(row=3, column=5, pady=10)
window.mainloop()
Ok, I think I improved Your code:
from tkinter import Tk, Button, Entry, Label
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
self.title('Nutrient calculator')
# entry
Label(self, text='Amount').grid(row=0, column=0)
self.amount = Entry(self, width=5, bg='light grey')
self.amount.grid(row=1, column=0)
# calories
Label(self, text='Calories').grid(row=0, column=1)
self.calories = Label(self)
self.calories.grid(row=1, column=1)
# proteins
Label(self, text='Proteins').grid(row=0, column=2)
self.proteins = Label(self)
self.proteins.grid(row=1, column=2)
# glucose
Label(self, text='Glucose').grid(row=0, column=3)
self.glucose = Label(self)
self.glucose.grid(row=1, column=3)
# lipids
Label(self, text='Lipids').grid(row=0, column=4)
self.lipids = Label(self)
self.lipids.grid(row=1, column=4)
# list of all labels
self.data_labels = [self.calories, self.proteins, self.glucose, self.lipids]
# error label for if no value is entered or it cannot be converted
self.error_label = Label(self, text='Use integer or float value!')
# stuff for adding multiple foods
self.do_add = False
self.nutrient_list = []
self.plus_btn = Button(self, text='Add', command=self.add)
self.plus_btn.grid(row=3, column=0, columnspan=4, sticky='nwes')
def display_values(self, value_list):
self.nutrient_list.append(value_list)
if len(self.nutrient_list) == 2 and not self.do_add:
self.nutrient_list.pop(0)
elif len(self.nutrient_list) > 2 and not self.do_add:
self.nutrient_list = [self.nutrient_list[-1]]
print(self.nutrient_list)
if self.do_add:
value_list = []
for i in range(len(self.nutrient_list[0])):
total_value = 0
for item in self.nutrient_list:
total_value += item[i]
value_list.append(total_value)
for text, label in zip(value_list, self.data_labels):
label.config(text=f'{text:.2f}')
self.do_add = False
def handle_value_error(self):
self.error_label.grid(row=2, column=0, columnspan=4)
def add(self):
self.do_add = True
self.amount.delete(0, 'end')
class Values:
def __init__(self, name, row, column, calories, proteins, glucose, lipids):
self.parent = root
self.name = name
self.row = row
self.column = column
self.calories = calories
self.proteins = proteins
self.glucose = glucose
self.lipids = lipids
self.stuff_list = [self.calories, self.proteins, self.glucose, self.lipids]
self.button = Button(self.parent, text=self.name, command=self.set_values)
self.button.grid(row=self.row, column=self.column, sticky='nwse')
def set_values(self):
value_list = []
value_ = self.parent.amount.get()
try:
formula = float(value_) / 100
self.parent.error_label.grid_forget()
for item in self.stuff_list:
item *= formula
value_list.append(item)
self.parent.display_values(value_list)
except ValueError:
self.parent.handle_value_error()
root = MainWindow()
kiwi = Values('Kiwi', 2, 4, calories=53, proteins=1.6, glucose=11.1, lipids=0.3)
banana = Values('Banana', 3, 4, calories=90, proteins=1.5, glucose=20.1, lipids=0)
root.mainloop()
it is not necessarily better however a few benefits from using this code are:
better organization (IMO) since it uses classes which make it pretty neat (however You have to have an understanding over them)
takes less space - what I mean is that now, to define a new food, You just have to initiate the Values class and give it the necessary arguments. You can take an example from the given instances.
possibly easier to expand (both because better organization and takes less space)
I edited the code so now it should have that functionality, the way it works is You choose an amount , then fruit and if You want to add more, press add button, then choose amount, press food and it will display the total so far, then again, if You want to add more press add and then put in an amount and press the fruit, currently the way to 'clear' is to press any food button and it should then reset the whole list and keep only the one that was just pressed and then repeat.