Python Forum
[Tkinter] Help running a loop inside a tkinter frame - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [Tkinter] Help running a loop inside a tkinter frame (/thread-40508.html)



Help running a loop inside a tkinter frame - Konstantin23 - Aug-08-2023

I have this password manager gui app made in tkinter, which consists of a frame stack corresponding to their respective frame classes to switch between frames. Each time a frame is switched, there is a certain set of variables which get passed around the frames. page_name and username are strings whereas services and data are lists. Now status is a bool variable who's default value is False, but while switching to the current frame, its value is modified to True. Now is there a way I can implement an endless loop which keeps running while the app runs, just to check if status is True, in which case, the option menu's values get updated. or is there a method I can implement which gets called when the current frame is raised inside the window or any other way in which the program can constantly check for status value?


import tkinter as tk
from customtkinter import CTkTextbox, CTkOptionMenu

class retrieve(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        tk.Frame.__init__(self, parent, bg="black", highlightthickness=5, highlightcolor='white')
        self.controller = controller
        head = tk.Label(self, bg="black", fg="white", text="STORED DATA",
                        font=("Terminal", 32))    
        
        data_disp = CTkTextbox(self, fg_color="black", text_color="white", font=("Terminal", 22, "bold"),
                                 scrollbar_button_color="white", scrollbar_button_hover_color="white",wrap=tk.WORD,
                                 corner_radius=0, width=450, height=250, border_width=0)
        option = tk.StringVar()
        def dropdown_callback(choice):
            services = self.controller.services
            #abc = ["A", "b", "abc"]
            data = self.controller.data
            i = services.index(choice)
            result = str(data[i])
            data_disp.configure(state=tk.NORMAL)
            data_disp.delete("0.0", tk.END)
            data_disp.insert("0.0", result)
            data_disp.configure(state=tk.DISABLED)
            print("dropdown clicked:", choice)
        
        # UPDATING THE WINDOW STATUS
        status = self.controller.status
        if status:
            services = self.controller.services
            self.service_list.configure(values=services)
            print("values updated")
        # ============================
        self.service_list = CTkOptionMenu(self, fg_color="black", text_color="white", font=("Terminal", 20, "bold"), 
                                         corner_radius=0, width=450, height=36, variable=option,
                                         command=dropdown_callback, dropdown_fg_color="black", 
                                         dropdown_text_color="white", dropdown_font=("Terminal", 20, "bold"),hover=False, 
                                         button_color="black", button_hover_color="white", dropdown_hover_color="black")
        self.service_list.set(">SERVICE NAME")
        back = tk.Button(self,
                          bg="black", fg="white",
                          text='BACK', font=("Terminal", 18, "bold"),
                          command=lambda: controller.show_frame(page_name="menu", username=self.controller.username, 
                                                                 services=self.controller.services, data=self.controller.data, status=self.controller.status),
                          activebackground="black",
                          relief=tk.SOLID,
                          borderwidth=0,
                          padx=16, pady=0, cursor="hand2")
        entNote = tk.Label(self,bg="black", fg="white", text="(enter)",
                           font=("Terminal", 10))

        head.place(relx=0.5, rely=0.1, anchor=tk.CENTER)
        self.service_list.place(relx=0.1, rely=0.3, y=-10,x=-35,anchor=tk.W)
        data_disp.place(relx=0.1, rely=0.45, x=-30, y=65,anchor=tk.W)
        back.place(relx=0.5, rely=0.9, anchor=tk.CENTER)
        entNote.place(relx=0.5, rely=0.9, y=20, anchor=tk.CENTER)
        controller.exitButton(self)
        controller.homeButton(self) 
        
    def binds(self):
        self.focus_set()
        self.controller.bind('<Return>', lambda x: self.controller.show_frame(page_name="menu", username=self.controller.username, 
                                                                               services=self.controller.services, data=self.controller.data, status=self.controller.status))
Also I tried implementing like so:
while True:
            status = self.controller.status
            if status:
                services = self.controller.services
                self.service_list.configure(values=services)
                print("values updated")
                break
but on running the app, it gets freezed and then crashes.

PS: I tried tkinter binding methods too but looks like they dont work with the custom tkinter widgets I am using.


RE: Help running a loop inside a tkinter frame - Gribouillis - Aug-08-2023

(Aug-08-2023, 07:19 PM)Konstantin23 Wrote: Now is there a way I can implement an endless loop which keeps running while the app runs, just to check if status is True, in which case, the option menu's values get updated.
How does the status change? Can't you just update the option menu's values when the program changes the status? It looks like an observer pattern. Or does the status change unpredictably?


RE: Help running a loop inside a tkinter frame - menator01 - Aug-08-2023

tkinter has it's own loop running. You could use after to update.

example of a simple clock

import tkinter as tk
from time import strftime

class Window:
    def __init__(self, parent):
        self.parent = parent
        self.label = tk.Label(parent, text='')
        self.label.pack(expand=True, fill='both')
        self.update()

    def update(self):
        clock = strftime('%H:%M:%S')
        self.label['text'] = clock
        self.label['font'] = (None, 28, 'normal')
        self.parent.after(1000, self.update)

if __name__ == '__main__':
    root = tk.Tk()
    root.geometry('300x200+200+200')
    Window(root)
    root.mainloop()



RE: Help running a loop inside a tkinter frame - Konstantin23 - Aug-10-2023

(Aug-08-2023, 07:39 PM)menator01 Wrote: tkinter has it's own loop running. You could use after to update.

example of a simple clock

import tkinter as tk
from time import strftime

class Window:
    def __init__(self, parent):
        self.parent = parent
        self.label = tk.Label(parent, text='')
        self.label.pack(expand=True, fill='both')
        self.update()

    def update(self):
        clock = strftime('%H:%M:%S')
        self.label['text'] = clock
        self.label['font'] = (None, 28, 'normal')
        self.parent.after(1000, self.update)

if __name__ == '__main__':
    root = tk.Tk()
    root.geometry('300x200+200+200')
    Window(root)
    root.mainloop()

Thank you so much! this was exactly the kind of solution I was looking for, implementing a self updating function.