tkinter - Printing current input + by mistake also previous inputs - python

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.

Related

Python, Tkinter: Calculating days left with tkcalendar

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.

How do I save my text from the textbox on tkinter to a text file?

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)

How to run tkinter's after event alongside another task?

I am trying to create a tkinter GUI for a script which performs some task. The task is triggered by clicking a start button, and I would like to add a dynamic label showing that the task is "in progress" by displaying:
"Working." → "Working.." → "Working..."
I referred to this post and wrote the following script. Here I used a progress bar to represent my "task", and was expecting the status label to change (as stated above) WHILE the progress bar is updating.
import tkinter as tk
class UI:
def __init__(self):
self.root = tk.Tk()
self.root.title('Hello World')
self.prog_Label = tk.Label(self.root, text='Progress')
self.prog_Label.grid(row=0, column=0, sticky=tk.W, padx=20, pady=(10, 0))
self.prog_Bar = tk.ttk.Progressbar(self.root)
self.prog_Bar.configure(value=0, mode='determinate', orient='horizontal')
self.prog_Bar.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=20, pady=5)
self.exe_Btn = tk.Button(self.root, text='Start', padx=15, command=self.run, relief='groove')
self.exe_Btn.grid(row=2, column=0, padx=80, pady=(40, 20), sticky=tk.E)
self.prog_Label = tk.Label(self.root, text='Status:-')
self.prog_Label.grid(row=3, column=0, sticky=tk.W, padx=20, pady=10)
self.root.mainloop()
def run(self):
self.update_status('Working')
n = 0
self.prog_Bar.configure(value=n, maximum=100000, mode='determinate', orient='horizontal')
for i in range(100000):
n += 1
self.prog_Bar.configure(value=n)
self.prog_Bar.update_idletasks()
def update_status(self, status=None):
if status is not None:
current_status = 'Status: ' + status
else:
current_status = self.prog_Label['text']
if current_status.endswith('...'):
current_status = current_status.replace('...', '')
else:
current_status += '.'
self.prog_Label['text'] = current_status
self.prog_Label.update_idletasks()
self._status = self.root.after(1000, self.update_status)
if __name__ == '__main__':
ui = UI()
However, the program behaves in a way that, when the start button is clicked, although the status label changes from '-' to 'Working' immediately, it only starts to add the dots after the progress bar reaches the end.
Is there a way to modify it so as to achieve my purpose?
I changed your structure a little so your task is now in its own class, instead of sleeping you would perform the task there. I added a thread for the task as i assumed that it would need its own process, this stops the application freezing as it would block the main UI loop.
import threading
import time
import tkinter as tk
import tkinter.ttk as ttk
class Task:
def __init__(self):
self.percent_done = 0
threading.Thread(target = self.run).start()
def run(self):
while self.percent_done < 1:
self.percent_done += 0.1
# Do your task here
time.sleep(0.5)
self.percent_done = 1
class Application():
def __init__(self):
self.root = tk.Tk()
self.root.title("Window Title")
self.task = None
self.label_dots = 0
self.prog_bar = tk.ttk.Progressbar(self.root)
self.prog_bar.configure(value=0, maximum=100, mode='determinate', orient='horizontal')
self.prog_bar.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=20, pady=5)
self.run_btn = tk.Button(self.root, text='Start', padx=15, command=self.start_task, relief='groove')
self.run_btn.grid(row=2, column=0, padx=80, pady=(40, 20), sticky=tk.E)
self.prog_label = tk.Label(self.root, text='Status: -')
self.prog_label.grid(row=3, column=0, sticky=tk.W, padx=20, pady=10)
def start_task(self):
self.task = Task()
self.update_ui()
def update_ui(self):
# Percent is between 0 and 1
if 0 < self.task.percent_done < 1:
status = "Working"
self.label_dots += 1
self.label_dots = self.label_dots % 4
else:
status = "Finished"
self.label_dots = 0
self.prog_bar.configure(value=self.task.percent_done * 100)
label_text = "Status: - " + status + ("." * self.label_dots)
self.prog_label.config(text = label_text)
if status != "Finished":
self.root.after(1000, self.update_ui)
Application().root.mainloop()

How can i erase contents in a Label?

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()

How do I backspace and clear the last equation and also a quit button?

I tried this:
self.btnquit = button(calc_frame, "Quit", tk.destroy)
self.btnquit.pack(side = LEFT)
before self.input = ...
But it came out invalid syntax. And the backspace only works if its in front of the number but I want it to be able to ackspace the last number entered, clear the last equation and then:
from tkinter import *
from tkinter.font import Font
def button(frame, text, command=None):
ft = Font(family=('Verdana'), size=14)
return Button(frame, text=text, font=ft, width=3, command=command)
def frame(frame, side=LEFT, bg="black"):
f = Frame(frame, background=bg, padx=5, pady=5)
f.pack(side=side, expand=YES, fill=BOTH)
return f
class App:
def __init__(self, tk):
ft = Font(family=('Verdana'), size=14)
main = frame(tk)
l_frame = frame(main)
r_frame = frame(main)
calc_frame = frame(l_frame)
self.input = Entry(calc_frame, font=ft, width=15, background="white")
self.input.pack(side=TOP)
self.btn_frame = frame(calc_frame)
x, y = 0, 0
for key in ("()%C", "+-*/", "1234", "5678", "90.="):
for c in key:
if c == "=":
btn = button(self.btn_frame, c, self.equalAction)
elif c == "C":
btn = button(self.btn_frame, c, self.cleanAction)
else:
btn = button(self.btn_frame, c, lambda i=c: self.input.insert(INSERT, i))
btn.grid(row=x, column=y)
y += 1
x += 1
y = 0
self.log = Text(r_frame, font=Font(family=('Verdana'), size=10), width=25, height=14, background="yellow")
self.log.pack(side=RIGHT)
def cleanAction(self):
self.input.delete(0, END)
def equalAction(self):
tmp = self.input.get()
try:
result = tmp + "=" + str(eval(tmp))
self.log.insert(1.0, result + "\n");
print(result)
except Exception:
self.log.insert(1.0, "Wrong expression\n");
if __name__ == '__main__':
root = Tk()
root.title("Calculator")
root.geometry()
app = App(root)
root.mainloop()
You can bind function to BackSpace in __init__
only when cursor (focus) is in Entry
self.input.bind_all('<BackSpace>', self.cleanInput)
or for all situations
main.bind_all('<BackSpace>', self.cleanInput)
and than you can delete text in Entry and Text
def cleanInput(self, event):
self.input.delete(0, END)
self.log.delete(1.0, END)
BTW: the same way you can bind other keys - for example digits
else:
btn = button(self.btn_frame, c, lambda i=c: self.input.insert(INSERT, i))
main.bind_all(c, lambda event, i=c:self.input.insert(INSERT, i))
EDIT:
full working code:
(issue: at that moment when cursor is in Entry numbers are inserted twice - normaly and by binding)
# python 2.x
#from Tkinter import *
#from tkFont import Font
# python 3.x
from tkinter import *
from tkinter.font import Font
class App:
def __init__(self, tk):
self.tk = tk
self.tk.title("Calculator")
#self.tk.geometry()
self.button_font = Font(family=('Verdana'), size=14)
main_frame = self.create_frame(self.tk)
left_frame = self.create_frame(main_frame)
right_frame = self.create_frame(main_frame)
calc_frame = self.create_frame(left_frame)
self.btnquit = self.create_button(calc_frame, "Quit", self.tk.destroy)
self.btnquit.pack(side = LEFT)
self.log = Text(right_frame, font=Font(family=('Verdana'), size=10), width=25, height=14, background="yellow")
self.log.pack(side=RIGHT)
self.input_text = StringVar()
self.input = Entry(calc_frame, font=self.button_font, width=15, background="white", textvariable=self.input_text)
self.input.pack(side=TOP)
btn_frame = self.create_frame(calc_frame)
for x, key in enumerate( ("()%C", "+-*/", "1234", "5678", "90.=") ):
for y, c in enumerate(key):
if c == "=":
btn = self.create_button(btn_frame, c, self.equalAction)
elif c == "C":
btn = self.create_button(btn_frame, c, self.cleanAction)
else:
btn = self.create_button(btn_frame, c, lambda number=c: self.insertNumber(number))
#main.bind_all(c, lambda event, number=c: self.insertNumber(number))
btn.grid(row=x, column=y)
self.btn_backspace = self.create_button(btn_frame, "<-", self.deleteLastDigit)
self.btn_backspace.grid(row=5, column=2, columnspan=2, sticky="we")
self.btn_loop = self.create_button(btn_frame, "LOOP", self.loopAction)
self.btn_loop.grid(row=5, column=0, columnspan=2, sticky="we")
main_frame.bind_all('<BackSpace>', self.cleanAction)
main_frame.bind_all('<Escape>', self.deleteLastDigit)
def loopAction(self):
bedmas = [ "()", "x^n", "*/", "+-" ]
for element in bedmas:
self.log.insert(INSERT,"\n"+element)
# event=None to use function in command= and in binding
def deleteLastDigit(self, event=None):
self.input_text.set( self.input_text.get()[:-1] )
def insertNumber(self, number):
self.input_text.set( self.input_text.get() + number )
def cleanAction(self):
self.input_text.set("")
self.log.delete(1.0, END)
def equalAction(self):
tmp = self.input_text.get()
try:
result = tmp + "=" + str(eval(tmp))
self.log.insert(1.0, result + "\n");
print(result)
except Exception:
self.log.insert(1.0, "Wrong expression\n");
def create_button(self, frame, text, command=None):
return Button(frame, text=text, font=self.button_font, width=3, command=command)
def create_frame(self, frame, side=LEFT, bg="black"):
f = Frame(frame, background=bg, padx=5, pady=5)
f.pack(side=side, expand=YES, fill=BOTH)
return f
def run(self):
self.tk.mainloop()
#---------------------------------------------------------------------
if __name__ == '__main__':
App(Tk()).run()

Categories

Resources