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.
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.