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.
Related
I am making a GUI in Tkinter and the code prints some attributes of a class.
However, something makes it print the attributes from the current instance but also from the previous ones (sorry if the jargon is wrong, I'm really new to this).
So in the Todo-list GUI I have created, I will enter a task and specify some attributes, then print all the attributes.
The task name is then displayed in a listbox and all the attributes of the task should be printed to terminal at the same time - however, this is where it will print the current attributes which I have just entered but also the attributes from the previously added task.
This is the code and the print command is in the def show_task(): function.
from tkcalendar import * # Calendar module
import tkinter.messagebox # Import the messagebox module
task_list = []
task_types = ['Sparetime', 'School', 'Work']
class Task:
def __init__(self, n, type_, i, m, p, h): #(h, 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.connectivity = c
##self.work = w ##hours of work per day
##self.urgency = u
##self.note = n
##self.value = v
def show_tasks():
# for widget in task_frame.winfo_children():
# widget.destroy()
for task in task_list:
#listbox_tasks.insert(tkinter.END, *task_list) #(task_frame, text=f'{task.name} \n Type: {task.type} | Impact: {task.impact}| Manageability: {task.manageability} | Proximity: {task.proximity}').pack(fill='x')
print(
'Task:'+task.name +
'\n' +
'Type:' + task.type + '\n' +
'Impact:' + task.impact + '\n' +
'Manageability:' + task.manageability + '\n' +
'Proximity(Deadline):' + task.proximity + '\n' +
'Hours:' + task.hours + '\n'
)
def open_add_task():
taskwin = Toplevel(root)
taskwin.focus_force()
#TITLE
titlelabel = Label(taskwin, text='Title task concisely:').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').grid(column=0, row=2)
type_var = StringVar(value=task_types[2])
OptionMenu(taskwin, type_var, *task_types).grid(column=0, row=3, sticky='nsew')
#IMPACT
impactlabel = Label(taskwin, text='Impact').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').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', 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').grid(column=1, row=16)
hour_entry = Entry(taskwin, width=4, justify='center')
hour_entry.grid(column=1, row=17)
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()))
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', command=add_task).grid(column=2, row=18, sticky='ew')
def sort_tasks():
pass
def delete_task():
pass
#try:
#task_index = listbox_tasks.curselection()[0]
#listbox_tasks.delete(task_index)
#except:
#tkinter.messagebox.showwarning(title='Oops', 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()
Replace:
for task in task_list:
with:
task = task_list[-1]
since you want to print details for a single task and not every task in the list. You'll also want to unindent the print statement.
Another noob asking for help again. Here is my code. I am trying to collect my text from the textbox. I have searched for the solution on how to save it but it just opens the save file and doesn't save anything. What I am trying to do is to save the text into a file after I've listed data using my widgets as a save file but sadly, that's the only thing that does not work for me. Perhaps I did something wrong in trying to save it. I am trying to fix my function saving_file_txt.
class OrderWindow:
def __init__(self, master):
self.master = master
self.master.title("Order Window Page")
self.master.geometry("1500x800")
self.master.configure(background="azure")
self.frame = Frame(self.master)
self.frame.pack()
# Placeholder for the information when ordering
self.prod_no_var = StringVar() # Product No input placeholder
self.product_name_var = StringVar() # Product Name input placeholder
self.quantity_var = StringVar() # Quantity input placeholder
self.prod_cost_var = StringVar() # Product Cost input placeholder
self.subtotal_var = StringVar() # Subtotal input placeholder
######################### Ordering Frame ################################
# Frame 1 - Ordering Details
self.order_detail_frame = Frame(self.frame, bg="azure")
self.order_detail_frame.grid(row=1, column=0)
self.basket_frame = Frame(self.frame)
self.basket_frame.grid(row=1, column=1)
self.heading = Label(self.order_detail_frame, text="AAT Shopping Application",
font=("arial", 15, "bold")).grid(row=0, column=0, ipadx=25)
self.order_detail_lblFrame = LabelFrame(self.order_detail_frame, text="Order Details")
self.order_detail_lblFrame.grid(row=1, column=0, ipady=50)
self.basket_heading = Label(self.basket_frame,
text="Product No\t\tProduct Name\t\tProduct Quantity\t\tProduct Price\t\tSubtotal"
).grid(row=0, column=0, columnspan=4, sticky="ne", ipadx=10)
self.basket_textbox = Text(self.basket_frame)
self.basket_textbox.grid(row=1, column=0, columnspan=4)
###########################Labels#############################
self.order_no = Label(self.order_detail_lblFrame, text="Order No").grid(row=0, column=0)
self.prod_name_lbl = Label(self.order_detail_lblFrame, text="Product Name").grid(row=1, column=0)
self.prod_qty_lbl = Label(self.order_detail_lblFrame, text="Quantity").grid(row=2, column=0)
self.prod_cost_lbl = Label(self.order_detail_lblFrame, text="Product Cost").grid(row=3, column=0)
self.subtotal_lbl = Label(self.order_detail_lblFrame, text="Sub Total").grid(row=4, column=0)
# Entry and Option Menu for ordering
########################### Product Combo Box #############################
self.prod_name_cb = ttk.Combobox(self.order_detail_lblFrame, textvariable=self.product_name_var)
self.prod_name_cb.grid(row=1, column=1, padx=35)
self.prod_name_cb["value"] = ("", "Gundam", "Starwars", "Paw Patrol", "Peppa Pig", "Cars Disney", "Teddy Bear")
self.prod_name_cb.current(0)
########################## Entry Box #############################
self.prod_no_entry = Entry(self.order_detail_lblFrame, textvariable=self.prod_no_var)
self.prod_no_entry.grid(row=0, column=1)
self.order_qty_entry = Entry(self.order_detail_lblFrame, textvariable=self.quantity_var)
self.order_qty_entry.grid(row=2, column=1)
self.order_cost_entry = Entry(self.order_detail_lblFrame, textvariable=self.prod_cost_var, state="disabled")
self.order_cost_entry.grid(row=3, column=1)
self.order_subtotal_entry = Entry(self.order_detail_lblFrame, textvariable=self.subtotal_var,
state="disabled")
self.order_subtotal_entry.grid(row=4, column=1) # Repeated line because it returns none value which gives error
########################## Buttons #############################
self.add_button = Button(self.order_detail_lblFrame, text="Add", command=self.add_item).grid(row=6, column=0)
self.delete_button = Button(self.order_detail_lblFrame, text="Delete", command=self.delete_item).grid(row=7,
column=0)
self.reset_button = Button(self.order_detail_lblFrame, text="Reset", command=self.reset_entry).grid(row=8,
column=0)
self.category_button = Button(self.order_detail_lblFrame, text="View products",
command=self.open_catalogue).grid(row=9, column=0)
self.save_basketfile_button = Button(self.order_detail_lblFrame, text="Save Reciept",
command=self.saving_file_txt
).grid(row=6, column=1)
self.pay_button = Button(self.order_detail_lblFrame, text="Checkout",
command=self.checkout_item).grid(row=7, column=1)
self.screenshot_button = Button(self.order_detail_lblFrame, text="Screenshot Window",
command=self.screenshoot_screen).grid(row=8, column=1)
self.exit_window_button = Button(self.order_detail_lblFrame, text="Exit",
command=self.exit_window).grid(row=9, column=1)
def add_item(self):
global total
item_dict = {"": 0, "Gundam": 10, "Starwars": 20, "Paw Patrol": 30, "Peppa Pig": 15, "Cars Disney": 15,
"Teddy Bear": 10}
order_no = self.prod_no_var.get()
item = self.product_name_var.get()
price = (self.prod_cost_var.get())
qty = int(self.quantity_var.get())
for product, cost in item_dict.items():
if item == product:
price = cost
total = round(price * qty, 2)
self.prod_no_var.set(int(order_no) + 1)
self.prod_cost_var.set("£" + str(price))
self.subtotal_var.set("£" + str(total))
self.basket_textbox.insert(END, self.prod_no_var.get() + "\t\t" + self.product_name_var.get() + "\t\t\t" +
self.quantity_var.get() + "\t\t" + self.prod_cost_var.get() + "\t\t" +
self.subtotal_var.get() + "\n")
def delete_item(self):
self.basket_textbox.delete("1.0", "2.0")
def reset_entry(self):
self.prod_no_var.set("")
self.product_name_var.set("")
self.quantity_var.set("")
self.prod_cost_var.set("")
self.subtotal_var.set("")
def checkout_item(self):
self.newWindow = Toplevel(self.master)
self.app = PaymentWindow(self.newWindow)
def open_catalogue(self):
self.newWindow = Toplevel(self.master)
self.app = CatalogueWindow(self.newWindow)
def exit_window(self):
self.master.destroy()
def screenshoot_screen(self):
window_screenshot = pyautogui.screenshot()
file_path = filedialog.asksaveasfilename(defaultextension=".png")
window_screenshot.save(file_path)
def saving_file_txt(self):
filetext = self.basket_textbox.get("1.0", "end-1c")
save_text = filedialog.asksaveasfilename(
defaultextension="txt",
filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],
)
filetext.save(save_text)
I too am a newb , but this seems crazy confusing to utilize a class for a new window in tkinter.
Maybe try to simplify by utilizing tkinter.Toplevel() and then sourcing your logical functions from there. eliminate the need for so many self calls and just update forms after submission and save. A simplified example below.
# import libraries (i use as tk to reduce the full import on launch)
import tkinter as tk
client_orders = [] # List of orders
def new_order_popup():
new_order_window.deiconify() # used to open the new order window (toplevel window)
class NEW_ORDER: # new order class, simplified for example)
def __init__(self, product_num, product_name, product_price):
self.product_num = product_num
self.product_name = product_name
self.product_price = product_price
def new_order(product_num, product_name, product_price): # creates each new order when
called.
new_order_window.deiconify()
input_product_num = pro_num_entry.get()
input_product_name = pro_name_entry.get()
input_product_price = float(pro_price_entry.get())
newOrder = NEW_ORDER(input_product_num, input_product_name, input_product_price)
return newOrder
def sub_(): # action when button pressed for submit/save
customer_order = new_order(product_num=str, product_name=str, product_price=float)
price_str = str(customer_order.product_price)
client_orders.append(customer_order)
order_string = (customer_order.product_num,' : ', customer_order.product_name,' :
', price_str,'\n')
print(order_string)
txt_file = open(f'text_doc.txt', 'a')
txt_file.writelines(order_string)
txt_file.close()
def sub_ex(): # same as other button but closes toplevel window.
customer_order = new_order(product_num=str, product_name=str, product_price=float)
price_str = str(customer_order.product_price)
client_orders.append(customer_order)
order_string = (customer_order.product_num, ' : ', customer_order.product_name, '
: ', price_str, '\n')
print(order_string)
txt_file = open(f'text_doc.txt', 'a')
txt_file.writelines(order_string)
txt_file.close()
new_order_window.withdraw()
#main window tkinter code. (at bottom eleviates complicated poiubters abd calls)
main = tk.Tk()
main.geometry('300x100')
main.title('Some Ordering System')
#button that does something
new_order_button = tk.Button(main)
new_order_button.configure(text='NewOrder', command = lambda: new_order_popup())
new_order_button.pack(pady=25)
#secondary window
new_order_window = tk.Toplevel(main)
new_order_window.geometry('300x200')
new_order_window.withdraw()
list_label = tk.Label(new_order_window)
list_label.configure(text='Prod. Num.\nProd. Name.\nProd. Price.')
list_label.place(anchor=tk.NW, x=15, y=15)
pro_num_entry = tk.Entry(new_order_window)
pro_num_entry.configure(width=20)
pro_num_entry.place(anchor=tk.NW, x=100, y=15)
pro_name_entry = tk.Entry(new_order_window)
pro_name_entry.configure(width=20)
pro_name_entry.place(anchor=tk.NW, x=100, y=35)
pro_price_entry = tk.Entry(new_order_window)
pro_price_entry.configure(width=20)
pro_price_entry.place(anchor=tk.NW, x=100, y=55)
submit_button = tk.Button(new_order_window)
submit_button.configure(text='Submit', command = lambda: sub_())
submit_button.place(anchor=tk.NW, x=35, y=100)
submit_exit_button = tk.Button(new_order_window)
submit_exit_button.configure(text='Submit and exit', command = lambda: sub_ex())
submit_exit_button.place(anchor=tk.NW, x=100, y=100)
main.mainloop()
launch: (mainwindow)
click:(toplevel)
output:(txt_file)
Hope this helps a bit. sometimes the answer is in the nested mess with my projects.
There is no save() function for string (filetext). You need to open the selected file (save_text) in write mode and save the text content to the file:
def saving_file_txt(self):
filetext = self.basket_textbox.get("1.0", "end-1c")
save_text = filedialog.asksaveasfilename(
defaultextension="txt",
filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],
)
if save_text:
with open(save_text, "w") as f:
f.write(filetext)
There's no save() method that can be used to save data; instead, you have to "manually" save the data. You can use the following commands to save the data:
open(filename, 'w').write(data)
After testing out many times and reading Stackoverflow for several hours, I decided to right this question. My Text (part of the bigger code) is below:
import pandas as pd
import datetime as dt
from tkinter import *
import tkinter.filedialog
from tkinter import messagebox
def test_click():
global ipt_dt
global coef
global z
global w
z = item_prosp['Accrual_Start'].min()
w = item_prosp['Accrual_End'].max()
ipt_d = tkvar_d.get()
ipt_m = tkvar_m.get()
ipt_y = tkvar_y.get()
x = 0
while x == 0:
ipt = str(ipt_d + '/'+ ipt_m + '/' + ipt_y)
try:
ipt_dt = dt.datetime.strptime(ipt, "%d/%b/%Y")
if ipt_dt < z or ipt_dt > w:
messagebox.showinfo("Error", "The input date is outside scope date")
else:
print("Date ok")
x =+ 1
except:
messagebox.showerror("Error", "The input date is not valid")
ipt_d = 0
ipt_m = 0
ipt_y = 0
continue
And the tkinter section of the code that generate the inputs is:
#Question 1 - Evaluation date
label4 = Label(window, text='Please inform the valuation date :', bg='white').grid(row=13, column=0, columnspan=3, pady=2, sticky=W)
tkvar_d = StringVar(window)
tkvar_m = StringVar(window)
tkvar_y = StringVar(window)
choices_d = ['1', '2', '3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31']
choices_m = ['Jan', 'Feb', 'Mar','Apr','May','Jun','Jul','Aug','Sep','Oct', 'Nov', 'Dec']
choices_y = ['2018','2019', '2020', '2021','2022','2023','2024','2025','2026','2027','2028','2029','2030']
popupmenu_d = OptionMenu(window, tkvar_d, *choices_d)
popupmenu_m = OptionMenu(window, tkvar_m, *choices_m)
popupmenu_y = OptionMenu(window, tkvar_y, *choices_y)
label5 = Label(window, text='Day :', bg='white').grid(row=14, column=0, sticky=E+W)
popupmenu_d.grid(row=15, column=0, padx=2, sticky=E+W)
label6 = Label(window, text='Month :', bg='white').grid(row=14, column=1, sticky=E+W)
popupmenu_m.grid(row=15, column=1, padx=2, sticky=E+W)
label7 = Label(window, text='Year :', bg='white').grid(row=14, column=2, sticky=E+W)
popupmenu_y.grid(row=15, column=2, padx=2, sticky=E+W)
Button(window, text="Test Date", width=10, command=test_click).grid(row=15, column=3, padx=5, pady=10, sticky=W)
The sample value for W when the file is run is:
2018-04-18 00:00:00
and for Z is:
2018-04-18 00:00:00
My need is to import a file (externally built and already structured), read 2 values from it (variables Z and W in the code) and compare it with an input variable (ipt_dt) which is a date filled in by the user through 3 dropdown menus from tkinter.
The error is that the try is not going through the if statement and it never prints out if the input is outside the scope date. Everytime I enter a date smaller than the minimum date or higher than the maximum date it returns the showerror message eventhou it pritns the "Date ok".
Anyone has any idea on how to solve this or why my fi is being ignored?
Thanks!
I looked at your originally posted code and you load the Excel into a df with the load_click function. But you don't actually run the load_click function anywhere, so the dataframe isn't loaded and so z and w aren't filled.
If you change the click1() function as follows, then it should work (it did for me with some sample data).
def click1():
global a
a = tkinter.filedialog.askopenfilename(initialdir = "/",title = "Select file", filetypes = ( ("Excel file", "*.xlsx"), ("All files", "*.*") ) )
output1.insert(END, a)
global a1
a1 = output1.get()
load_click()
Or add a seperate 'load' button if you want (at the bottom of the #File1 part):
Button(window, text="Load", width=6, command=load_click).grid(row=4, column=3, padx=5, sticky=W)
You might also want to add another x = 1 in the if-statement. Otherwise the messagebox will keep popping up due to the while loop, making it impossible to correct the input date.
x = 0
while x == 0:
ipt = str(ipt_d + '/'+ ipt_m + '/' + ipt_y)
try:
ipt_dt = dt.datetime.strptime(ipt, "%d/%b/%Y")
print type(ipt_dt)
if (ipt_dt < z) or (ipt_dt > w):
messagebox.showinfo("Error", "The input date is outside scope date")
x = 1 # I've added this one
else:
print("Date ok")
x =+ 1
except:
messagebox.showerror("Error", "The input date is not valid")
ipt_d = 0
ipt_m = 0
ipt_y = 0
continue
I'm trying to create a menu in tkinter, in which there will be different conditions. One of them will be the date choice. Now you need to enter the date manually. I want to make a calendar. I thought to use the answer to this question and the code to which there is a link. But I do not know how to use it with my code.
Below is the code of my menu:
import numpy as np
items5 = np.arange(1,14)
items6 = np.arange(1, 28)
items7 = np.arange(4, 28)
choose_y_n = ['yes', 'no']
items12 = np.arange(50, 100)
items13 = np.arange(0,15)
from tkinter import*
class MyOptionMenu(OptionMenu):
def __init__(self, master, status, *options):
self.var = StringVar(master)
self.var.set(status)
OptionMenu.__init__(self, master, self.var, *options)
self.config(font=('Arial',(10)),bg='white',width=20)
self['menu'].config(font=('Arial',(10)),bg='white')
root = Tk()
optionList5 = items5
optionList6 = items6
optionList7 = items7
optionList8 = choose_y_n
optionList12 = items12
optionList13 = items13
lab = Label(root, text="Enter the date in the format 'dd.mm.yyyy'", font="Arial 10", anchor='w')
ent1 = Entry(root,width=20,bd=3)
lab5 = Label(root, text="condition №1", font="Arial 10", anchor='w')
mymenu5 = MyOptionMenu(root, '2', *optionList5)
lab6 = Label(root, text="condition №2", font="Arial 10", anchor='w')
mymenu6 = MyOptionMenu(root, '12', *optionList6)
lab7 = Label(root, text="condition №3", font="Arial 10", anchor='w')
mymenu7 = MyOptionMenu(root, '13', *optionList7)
lab8 = Label(root, text="condition №4", font="Arial 10", anchor='w')
mymenu8 = MyOptionMenu(root, 'yes', *optionList8)
lab12 = Label(root, text="condition №5", font="Arial 10", anchor='w')
mymenu12 = MyOptionMenu(root, '80', *optionList12)
lab13 = Label(root, text="condition №6", font="Arial 10", anchor='w')
mymenu13 = MyOptionMenu(root, '9', *optionList13)
labels = [lab, lab5, lab6, lab7, lab8, lab12, lab13]
mymenus = [ent1, mymenu5, mymenu6, mymenu7, mymenu8, mymenu12, mymenu13]
def save_selected_values():
global values1
values1 = [ent1.get(), mymenu5.var.get(), mymenu6.var.get(), mymenu7.var.get(), mymenu8.var.get(),
mymenu12.var.get(), mymenu13.var.get()]
print(values1)
def close_window():
root.destroy()
button = Button(root, text="Ok", command=save_selected_values)
button1 = Button(root, text="Quit", command=close_window)
for index, (lab, mymenu) in enumerate(zip(labels, mymenus)):
lab.grid(row=index, column=0)
mymenu.grid(row=index, column=1)
button.grid(row=index, column=2)
button1.grid(row=index, column=3)
root.mainloop()
For me, it's important to save the date in a variable.
I will be very grateful for any recommendations!
UPD
My new code is below.
It seems that my code doesn't save the date at all.
I just don't understand how to get the date as a variable. What am I doing wrong?
import numpy as np
items5 = np.arange(1,14)
items6 = np.arange(1, 28)
items7 = np.arange(4, 28)
choose_y_n = ['yes', 'no']
items12 = np.arange(50, 100)
items13 = np.arange(0,15)
from tkinter import*
import tkinter.font as tkFont
from tkinter import ttk
def get_calendar(locale, fwday):
# instantiate proper calendar class
if locale is None:
return calendar.TextCalendar(fwday)
else:
return calendar.LocaleTextCalendar(fwday, locale)
class Calendar(ttk.Frame):
# XXX ToDo: cget and configure
datetime = calendar.datetime.datetime
timedelta = calendar.datetime.timedelta
def __init__(self, master=None, **kw):
"""
WIDGET-SPECIFIC OPTIONS
locale, firstweekday, year, month, selectbackground,
selectforeground
"""
# remove custom options from kw before initializating ttk.Frame
fwday = kw.pop('firstweekday', calendar.MONDAY)
year = kw.pop('year', self.datetime.now().year)
month = kw.pop('month', self.datetime.now().month)
locale = kw.pop('locale', None)
sel_bg = kw.pop('selectbackground', '#ecffc4')
sel_fg = kw.pop('selectforeground', '#05640e')
self._date = self.datetime(year, month, 1)
self._selection = None # no date selected
ttk.Frame.__init__(self, master, **kw)
self._cal = get_calendar(locale, fwday)
self.__setup_styles() # creates custom styles
self.__place_widgets() # pack/grid used widgets
self.__config_calendar() # adjust calendar columns and setup tags
# configure a canvas, and proper bindings, for selecting dates
self.__setup_selection(sel_bg, sel_fg)
# store items ids, used for insertion later
self._items = [self._calendar.insert('', 'end', values='')
for _ in range(6)]
# insert dates in the currently empty calendar
self._build_calendar()
# set the minimal size for the widget
self._calendar.bind('<Map>', self.__minsize)
def __setitem__(self, item, value):
if item in ('year', 'month'):
raise AttributeError("attribute '%s' is not writeable" % item)
elif item == 'selectbackground':
self._canvas['background'] = value
elif item == 'selectforeground':
self._canvas.itemconfigure(self._canvas.text, item=value)
else:
ttk.Frame.__setitem__(self, item, value)
def __getitem__(self, item):
if item in ('year', 'month'):
return getattr(self._date, item)
elif item == 'selectbackground':
return self._canvas['background']
elif item == 'selectforeground':
return self._canvas.itemcget(self._canvas.text, 'fill')
else:
r = ttk.tclobjs_to_py({item: ttk.Frame.__getitem__(self, item)})
return r[item]
def __setup_styles(self):
# custom ttk styles
style = ttk.Style(self.master)
arrow_layout = lambda dir: (
[('Button.focus', {'children': [('Button.%sarrow' % dir, None)]})]
)
style.layout('L.TButton', arrow_layout('left'))
style.layout('R.TButton', arrow_layout('right'))
def __place_widgets(self):
# header frame and its widgets
hframe = ttk.Frame(self)
lbtn = ttk.Button(hframe, style='L.TButton', command=self._prev_month)
rbtn = ttk.Button(hframe, style='R.TButton', command=self._next_month)
self._header = ttk.Label(hframe, width=15, anchor='center')
# the calendar
self._calendar = ttk.Treeview(show='', selectmode='none', height=7)
# pack the widgets
hframe.pack(in_=self, side='top', pady=4, anchor='center')
lbtn.grid(in_=hframe)
self._header.grid(in_=hframe, column=1, row=0, padx=12)
rbtn.grid(in_=hframe, column=2, row=0)
self._calendar.pack(in_=self, expand=1, fill='both', side='bottom')
def __config_calendar(self):
cols = self._cal.formatweekheader(3).split()
self._calendar['columns'] = cols
self._calendar.tag_configure('header', background='grey90')
self._calendar.insert('', 'end', values=cols, tag='header')
# adjust its columns width
font = tkFont.Font()
maxwidth = max(font.measure(col) for col in cols)
for col in cols:
self._calendar.column(col, width=maxwidth, minwidth=maxwidth,
anchor='e')
def __setup_selection(self, sel_bg, sel_fg):
self._font = tkFont.Font()
self._canvas = canvas = tkinter.Canvas(self._calendar,
background=sel_bg, borderwidth=0, highlightthickness=0)
canvas.text = canvas.create_text(0, 0, fill=sel_fg, anchor='w')
canvas.bind('<ButtonPress-1>', lambda evt: canvas.place_forget())
self._calendar.bind('<Configure>', lambda evt: canvas.place_forget())
self._calendar.bind('<ButtonPress-1>', self._pressed)
def __minsize(self, evt):
width, height = self._calendar.master.geometry().split('x')
height = height[:height.index('+')]
self._calendar.master.minsize(width, height)
def _build_calendar(self):
year, month = self._date.year, self._date.month
# update header text (Month, YEAR)
header = self._cal.formatmonthname(year, month, 0)
self._header['text'] = header.title()
# update calendar shown dates
cal = self._cal.monthdayscalendar(year, month)
for indx, item in enumerate(self._items):
week = cal[indx] if indx < len(cal) else []
fmt_week = [('%02d' % day) if day else '' for day in week]
self._calendar.item(item, values=fmt_week)
def _show_selection(self, text, bbox):
"""Configure canvas for a new selection."""
x, y, width, height = bbox
textw = self._font.measure(text)
canvas = self._canvas
canvas.configure(width=width, height=height)
canvas.coords(canvas.text, width - textw, height / 2 - 1)
canvas.itemconfigure(canvas.text, text=text)
canvas.place(in_=self._calendar, x=x, y=y)
# Callbacks
def _pressed(self, evt):
"""Clicked somewhere in the calendar."""
x, y, widget = evt.x, evt.y, evt.widget
item = widget.identify_row(y)
column = widget.identify_column(x)
self.event_generate("<<CalendarChanged>>")
if not column or not item in self._items:
# clicked in the weekdays row or just outside the columns
return
item_values = widget.item(item)['values']
if not len(item_values): # row is empty for this month
return
text = item_values[int(column[1]) - 1]
if not text: # date is empty
return
bbox = widget.bbox(item, column)
if not bbox: # calendar not visible yet
return
# update and then show selection
text = '%02d' % text
self._selection = (text, item, column)
self._show_selection(text, bbox)
def _prev_month(self):
"""Updated calendar to show the previous month."""
self._canvas.place_forget()
self._date = self._date - self.timedelta(days=1)
self._date = self.datetime(self._date.year, self._date.month, 1)
self._build_calendar() # reconstuct calendar
def _next_month(self):
"""Update calendar to show the next month."""
self._canvas.place_forget()
year, month = self._date.year, self._date.month
self._date = self._date + self.timedelta(
days=calendar.monthrange(year, month)[1] + 1)
self._date = self.datetime(self._date.year, self._date.month, 1)
self._build_calendar() # reconstruct calendar
# Properties
#property
def selection(self):
"""Return a datetime representing the current selected date."""
if not self._selection:
return None
year, month = self._date.year, self._date.month
return self.datetime(year, month, int(self._selection[0]))
class MyOptionMenu(OptionMenu):
def __init__(self, master, status, *options):
self.var = StringVar(master)
self.var.set(status)
OptionMenu.__init__(self, master, self.var, *options)
self.config(font=('Arial',(10)),bg='white',width=20)
self['menu'].config(font=('Arial',(10)),bg='white')
root = Tk()
optionList5 = items5
optionList6 = items6
optionList7 = items7
optionList8 = choose_y_n
optionList12 = items12
optionList13 = items13
lab = Label(root, text="Select date", font="Arial 10", anchor='w')
ent1 = Calendar(firstweekday=calendar.SUNDAY)
lab5 = Label(root, text="condition №1", font="Arial 10", anchor='w')
mymenu5 = MyOptionMenu(root, '2', *optionList5)
lab6 = Label(root, text="condition №2", font="Arial 10", anchor='w')
mymenu6 = MyOptionMenu(root, '12', *optionList6)
lab7 = Label(root, text="condition №3", font="Arial 10", anchor='w')
mymenu7 = MyOptionMenu(root, '13', *optionList7)
lab8 = Label(root, text="condition №4", font="Arial 10", anchor='w')
mymenu8 = MyOptionMenu(root, 'yes', *optionList8)
lab12 = Label(root, text="condition №5", font="Arial 10", anchor='w')
mymenu12 = MyOptionMenu(root, '80', *optionList12)
lab13 = Label(root, text="condition №6", font="Arial 10", anchor='w')
mymenu13 = MyOptionMenu(root, '9', *optionList13)
labels = [lab, lab5, lab6, lab7, lab8, lab12, lab13]
mymenus = [ent1, mymenu5, mymenu6, mymenu7, mymenu8, mymenu12, mymenu13]
def save_selected_values():
global values1
values1 = [ent1, mymenu5.var.get(), mymenu6.var.get(), mymenu7.var.get(), mymenu8.var.get(),
mymenu12.var.get(), mymenu13.var.get()]
print(values1)
def on_calendar_changed(event):
date = cal.selection
datestr = "{:%d.%m.%Y}".format(date)
print(datestr)
dateVar.set(datestr)
def close_window():
root.destroy()
button = Button(root, text="Ok", command=save_selected_values)
button1 = Button(root, text="Quit", command=close_window)
for index, (lab, mymenu) in enumerate(zip(labels, mymenus)):
lab.grid(row=index, column=0)
mymenu.grid(row=index, column=1)
button.grid(row=index, column=2)
button1.grid(row=index, column=3)
root.mainloop()
That ttkcalendar.py needs a little help I reckon. You want to perform an action when the calendar widget has a new date selected and to do that you should bind to an event. However it is not generating any at the moment so at the end of the _pressed method add the following line to generate a virtual event you can bind to:
self.event_generate("<<CalendarChanged>>")
You can then add this widget to your UI and bind a function to this CalendarChanged virtual event as shown:
def on_calendar_changed(event):
date = cal.selection
datestr = "{:%d.%m.%Y}".format(date)
print(datestr)
dateVar.set(datestr)
cal.bind("<<CalendarChanged>>", on_calendar_changed)
Here I set a StringVar named dateVar as the textvariable of the ent1 widget. Now when the calendar selection changes, it puts the properly formatted string into your entry widget.
You would do well to convert from the OptionMenu widget to ttk.Combobox widgets and generally use ttk widgets in preference to the older Tk widgets.
Sorry for the mess
so I am making a seating chart, and I cant seem to get it working properly... again. I am trying to make the label reset every time i press the run button, any ideas?
#commands: add name , Run
#imports
import random
from time import sleep
from tkinter import *
#Console and background Handlers
Tables = 6
Names = []
def AddNames():
NewNames = e.get("1.0", 'end -1c')
if NewNames in Names:
print("Name Already exists")
elif NewNames == "":
print("Empty")
else:
Names.append(NewNames)
print(Names)
e.delete(1.0, END)
def Random():
RandomNum = random.randrange(Tables)
if RandomNum == 0:
RandomNum = random.randrange(Tables)
return RandomNum
def run():
X = 0
for i in Names:
#print(Names[X])
print("Table: " + str(Random()))
X += 1
#text = Label(popup, text = "")
text = Label(popup, text= Names[X] + "\n" + "Table: " + str(Random()))
text.pack()
#GUI Handler
root = Tk()
root.geometry("1024x768")
e = Text(root, bd = 10, font=("Comic Sans MS", 50) ,width = 15, height = 2)
e.pack()
popup = Toplevel()
popup.title("Seating Chart")
AddNameButton = Button(root, text = ("Add Name"), width = 15, height = 5, command = AddNames)
AddNameButton.pack()
RunButton = Button(root, text = ("Run"), width = 15, height = 5, command = run)
RunButton.pack()
root.mainloop()
I am trying to reset text every time the user presses the run button
import tkinter
from tkinter import ttk
import random
class MyApp:
def __init__(self):
self.root = tkinter.Tk()
self.seatwindow = None
self.root.title('Add Names')
self.currentname = tkinter.StringVar()
self._maxtables = tkinter.StringVar()
self.addednames = []
self.commandframe = ttk.Labelframe(self.root, text='Commands')
self.nameentry = ttk.Entry(self.root, textvariable=self.currentname)
self.addbutton = ttk.Button(self.root, text='Add Name', command=self.addname)
self.maxtablabel = ttk.Label(self.root, text='Tables: ')
self.maxtabentry = ttk.Entry(self.root, textvariable=self._maxtables)
self.genbutton = ttk.Button(self.commandframe, text='Run', command=self.generate)
self.resetbutton = ttk.Button(self.commandframe, text='Reset', command=self.reset)
self._maxtables.set('6')
self.nameentry.grid(row=0, column=0)
self.addbutton.grid(row=0, column=1, sticky='nsew')
self.maxtabentry.grid(row=1, column=1, sticky='nsw')
self.maxtablabel.grid(row=1, column=0, sticky='nse')
self.genbutton.grid(row=0, column=0, sticky='nsew')
self.resetbutton.grid(row=0, column=1, sticky='nsew')
self.commandframe.grid(row=2, column=0, columnspan=2, sticky='nsew')
self.nameentry.bind('<Return>', self.addname)
self.root.bind('<Control-Return>', self.generate)
def addname(self, event=None):
name = self.currentname.get()
if not(name == '' or name in self.addednames):
self.addednames.append(name)
self.currentname.set('')
else:
self.currentname.set('Name already added!')
def generate(self, event=None):
if not self.seatwindow == None:
self.seatwindow.destroy()
self.currentname.set('')
self.seatwindow = tkinter.Toplevel()
random.shuffle(self.addednames)
tables = []
for i in range(self.maxtables):
tableframe = ttk.Labelframe(self.seatwindow, text='Table ' + str(i + 1) + ':')
tableframe.grid(column=i, row=0, sticky='nsew')
tables.append(tableframe)
for index, name in enumerate(self.addednames):
namelabel = ttk.Label(tables[index%self.maxtables], text=name)
namelabel.grid(column=0, row=index//self.maxtables + 1)
def reset(self):
self.currentname.set('')
self.maxtables = 6
self.addednames = []
def run(self):
self.root.mainloop()
#property
def maxtables(self):
return int(self._maxtables.get())
MyApp().run()