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 key
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:
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 input
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