Hello. I am using python tkinter to create interface for my application. I have made a very bad spaghetti code initially and managed to get it to work without using the mainloop. I would like to improve my previous code and get my program to work properly with tkinter mainloop.
I have created an application class :
my main code starts like that:
After pressing that button, the code executed is:
The issue is:
I can see that canvas.delete("all") properly deletes all canvas widgets and Application_Intro code is being called to generate a new widgets HOWEVER, it does not seem to start a "fresh" task. It continues to execute where its left
For example, if I am in the middle of a task:
The code below is my task:
In short, I want to be able to press a button which would clear whole GUI, and and basically start a "new" tkinter GUI. But my current function does not stop the current mainloop even though it clears canvas and creates a new instance of Application_intro
I have created an application class :
class Application(tk.Frame):
flag_ota_button = 0
def __init__(self,master=None):
super().__init__(master)
self.master = master
def Create_canvas(self,canvas_width,canvas_height):
global canvas
canvas = tk.Canvas(self.master,bg='ivory2',width=canvas_width,height=canvas_height)
def Application_Intro(self):
print("starting new app")
global label_RED
global entry_input# define this as global so it can be read in the callback function
#canvas = tk.Canvas(self.master,bg='ivory2',width=canvas_width,height=canvas_height)
label1 = tk.Label(canvas,text = "SKENUOKITE BARKODA(GUID) ARBA DAIKTO RIVILINI KODA:",font='Helvetica 16 bold',bg='ivory2',foreground="red")
entry_input = tk.Entry(canvas) # entry = guid
entry_input.focus_set()
end_program_button = tk.Button(canvas, text="Baigti",font='Helvetica 12 bold', width=20, height=2, command=self.end_program)
restart_program_button = tk.Button(canvas, text="Restartuoti",font='Helvetica 12 bold', width=20, height=2, command =self.Restart)
ota_button = tk.Button(canvas, text="Atnaujinti",font='Helvetica 12 bold', width=20, height=2, command=self.OTA_gui)
remove_item_button = tk.Button(canvas, text="Isvalyti dezute",font='Helvetica 12 bold', width=20, height=2, command=self.Remove_item_gui)
new_operation_button = tk.Button(canvas, text="Nauja operacija",font='Helvetica 12 bold', width=20, height=2, command = self.New_operation)
canvas.create_text(960,20,text="PICK TO LIGHT",font='Helvetica 16 bold')
label_RED = canvas.create_window(960,75,window=label1)
self.user_input_entry=canvas.create_window(960,125,window=entry_input)
canvas.create_window(1210,200,window=ota_button)
canvas.create_window(960,200,window=remove_item_button)
canvas.create_window(710,200,window = new_operation_button)
canvas.create_window(1210,400,window = end_program_button)
canvas.create_window(710,400,window = restart_program_button)
entry_input.bind('<Return>',read_user_input)
canvas.pack()
def picking_gui(self):
self.devices = {}
device_list,serial_list = count_unique_devices(myConnection)
print("the list of devices=",device_list)
img_red_original = Image.open("camera_red.png")
img_red_original = img_red_original.resize((50,50),Image.ANTIALIAS)
self.img_red = ImageTk.PhotoImage(img_red_original)
img_green_original = Image.open("camera_green.png")
img_green_original = img_green_original.resize((50,50),Image.ANTIALIAS)
self.img_green = ImageTk.PhotoImage(img_green_original)
red_image = canvas.create_image(100,50,image=self.img_red,anchor='nw')
self.update_RED_label(label_RED,960,75,"Imkite daiktus is nurodytu dezuciu")
gaminio_kodas_text = "Gaminio kodas="+user_input
gaminio_serial_text = "Serial="+komplektacijos_Serial
gaminio_IMEI_Text = "IMEI="+komplektacijos_Imei
canvas.create_text(960,400,text=gaminio_kodas_text,font='Helvetica 12 bold')
canvas.create_text(960,425,text=gaminio_serial_text,font='Helvetica 12 bold')
canvas.create_text(960,450,text=gaminio_IMEI_Text,font='Helvetica 12 bold')
for x in range(0,len(device_list)):
self.devices[device_list[x]] = canvas.create_rectangle(20+(x*110),550,110+(x*110),640,fill='red')
canvas.create_text(65+(x*110),585,text=device_list[x],font='Helvetica 12 bold',fill="yellow")
canvas.create_text(65+(x*110),605,text=serial_list[x],font='Helvetica 10 bold',fill="yellow")
if(x>15):
self.devices[device_list[x]] = canvas.create_rectangle(20+(x*110),650,110+(x*110),740,fill='red')
canvas.create_text(55+(x*90),585,text=device_list[x],font='Helvetica 12 bold',fill="yellow")
canvas.create_text(65+(x*110),605,text=serial_list[x],font='Helvetica 10 bold',fill="yellow")
canvas.pack()
def update_rectangle_color_initial(self,device_name):
canvas.itemconfig(self.devices[device_name],fill="green")
self.last_device = device_name
def update_rectangle_color_last(self):
canvas.itemconfig(self.devices[self.last_device],fill="red")
def update_rectangle_color(self,device_name):
canvas.itemconfig(self.devices[self.last_device],fill="red")
canvas.itemconfig(self.devices[device_name],fill="green")
self.last_device = device_name
def refresh_app(self,delay):
#refresh_variables()
canvas.delete("all")
app.after(delay,lambda:self.Application_Intro())
def update_MAIN_label(self,label,x,y,text1):
global label_MAIN
canvas.delete(label_MAIN)
label_MAIN = canvas.create_text(x,y,text=text1,font="Helvetica 14 bold")
def update_RED_label(self,label,x,y,text1):
global label_RED
canvas.delete(label_RED)
label_RED = canvas.create_text(x,y,text=text1,fill="red",font='Helvetica 16 bold')
def make_new_textbox(self,text_input):
global label_RED
global new_textbox_entry
canvas.delete(label_RED)
canvas.delete(self.user_input_entry)
label=tk.Label(canvas,text = text_input,bg='ivory2',foreground="red",font='Helvetica 16 bold')
new_textbox_entry = tk.Entry(canvas)
new_textbox_entry.focus_set()
label_RED = canvas.create_window(960,75,window=label)
self.user_input_entry = canvas.create_window(960,125,window=new_textbox_entry)
new_textbox_entry.bind('<Return>',read_user_new_textbox)
def end_program(self):
print("end program")
def Restart(self):
print("restart")
restart_devices(myConnection,"RESTART")
self.refresh_app(1000)
def OTA_gui(self):
print("OTA gui")
def Remove_item_gui(self):
print("remove item gui")
def New_operation(self):
print("new_operation")
restart_devices(myConnection,"reset")
canvas.delete("all")
app.after(1000,self.Application_Intro)
print("new operation end")
def OTA_gui(self):
self.devices = []
if(self.flag_ota_button % 2 != 0):
canvas.delete(ota_label)
canvas.delete(ota_choices)
canvas.delete(ota_button)
self.flag_ota_button+=1
return
else:
self.devices = ["device1","device2","device3","device4","device5","device6","device7","device8","device9"]
device_list,serial_list = count_unique_devices(myConnection)#get list of unique device names from MYSQL DB
print("device list OTA=",device_list)
print("sertial list OTA=",serial_list)
label = tk.Label(canvas,text="Pasirinkti kuria dezute atnaujinti",font='Helvetica 12 bold')
choices = ttk.Combobox(canvas,values=self.devices)
choices.current(0)
button = tk.Button(canvas,text="Patvirtinti",command =lambda: self.device_confirmed(choices,"ota"))
self.ota_label = canvas.create_window(960,250,window=label)
self.ota_choices = canvas.create_window(960,300,window=choices)
self.ota_button = canvas.create_window(960,350,window=button)
self.flag_ota_button+=1
def device_confirmed(self,choices,status):
device = choices.get()
if(status == "ota"):
print("device=",device)
mqttc.publish(device+"/status","OTA")
canvas.delete(self.ota_label)
canvas.delete(self.ota_choices)
canvas.delete(self.ota_button)
else:
publish_mqtt_json_item_inside("",device,"","")
canvas.delete(remove_item_label)
canvas.delete(remove_item_choices)
canvas.delete(remove_item_button)
remove_item_from_device(myConnection,device)i use some global variables inside my class because I have other functions outside the class that access to those variables.my main code starts like that:
master = tk.Tk() app = Application(master=master) app.Create_canvas(1920,1080) app.Application_Intro() app.mainloop()As you can see from the function above, i am calling Application_intro function which is handles my main GUI. One of the GUI widgets is the "new operation" button:
After pressing that button, the code executed is:
def New_operation(self):
print("new_operation")
restart_devices(myConnection,"reset")
canvas.delete("all")
app.after(1000,self.Application_Intro)
print("new operation end")As you can see from the code above, the function deletes all previous canvas elements and calls new Application_intro. I just want to delete whatever happened during the previous task and start a fresh task. A fresg task is what I consider an idle state, The application intro creates a text entry and sits there untill I write something in the text box and press enter keyThe issue is:
I can see that canvas.delete("all") properly deletes all canvas widgets and Application_Intro code is being called to generate a new widgets HOWEVER, it does not seem to start a "fresh" task. It continues to execute where its left
For example, if I am in the middle of a task:
The code below is my task:
def handle_next_pick():
print("handling next pick")
global item_number
global flag_next_device
print("pick counter =",pick_counter)
if(pick_counter < Counter_global):
if(flag_next_device>0):
print("flag_next_device is higher than 1")
if(item_number > 0):#only check if it divides by counter if its higher then 0 to avoid glitch
if(item_number % Counter_global_temp==0):
item_number=item_number-(Counter_global_temp)
app.update_rectangle_color(Device_global_temp[item_number])
string = Device_global_temp[item_number]+"/"+"status"
mqttc.publish(string,"ACTIVE",1)
flag_next_device=0
if(update_DB==1):
update_DB_Quantity(myConnection)
else:
print("Dont need to update DB")
app.after(100,handle_next_pick)
else:
app.after(100,handle_next_pick)
print("wait for next command")
else:
app.after(1000,handle_end_of_picking)I am not gonna go into details about what this code does, but it waits for me to "initiate" the next pick.That is being done when I toggle a sensor on ESP32 device. When this task is started, it prints me the message ("wait for next command"). When I execute new_operation() which supposed to clear canvas and start a fresh task, it continues to print "wait for next command" but that should not be the case. Becuase I want to cancel the current task and just go to the idle state where I the program waits for my textbox inputIn short, I want to be able to press a button which would clear whole GUI, and and basically start a "new" tkinter GUI. But my current function does not stop the current mainloop even though it clears canvas and creates a new instance of Application_intro
