Python Forum
What to do to stop all these threads?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What to do to stop all these threads?
#1
Hi guys, sorry for my noobness again:

I noticed when I was closing my app the task icon on visual code studio was still running. So my app was not terminating accordingly:

I decided printing the processes were running after closing the window and noticed this list:

MainThread
Thread-3 (listen)
Thread-4 (process)
Thread-5 (create_popup)
Thread-6 (<lambda>)
Dummy-41

So, it has to do with threads and not correctly stopping them. I read some articles, tried sending stop signals, but I cant get it to work. I am having difficulties dealing probrably with pywebivew loop (that starts with webview.start) and the tkinter popup loop. I am sucessfully stopping the keyboard listener in my Keylistener class, however there is still a listener thread that I am now able to stop. And I dont know where these "lambda" and "Dummy41" threads come from.

Can someone please give me a starting point? I began writing the code without a solid base, and then I am realizing that I need to come back to build something more robust to have less problems in the future. Thanks.



class Api:
    def __init__(self):
        

        self.is_maximized = False
        self.events = []

    def create_and_position_window(self):
        monitor = get_monitors()[0]
        screen_width = monitor.width
        screen_height = monitor.height
        pos_x = (screen_width - WINDOW_WIDTH) // 2
        pos_y = (screen_height - WINDOW_HEIGHT) // 2

        self.window = webview.create_window(
            title=WINDOW_TITLE,
            url="index.html",
            frameless=False,
            resizable=True,
            js_api=self,
            min_size=(screen_width // 2, WINDOW_HEIGHT),
        )

        time.sleep(1)

        window = get_window()

        if window:
            window.moveTo(pos_x, pos_y)

        threading.Thread(target=self.call_load_handler_after_delay).start()

    def call_load_handler_after_delay(self):
        time.sleep(0.5)
        load_handler(self.window)



    def create_popup(tk_queue, key_listener_instance):
    
         print("Entered create_popup")  # Debugging
    
         while True:
         queue_data = tk_queue.get()
         msg, data = queue_data[:2]  # Only take the first two values

         current_window = getActiveWindow()
         current_win_title = current_window.title if current_window else "Unknown Window"
        
        if msg == "create_popup":
            print("About to stop listener and create popup")  # Debugging
            key_listener_instance.stop_listener()

            windows = gw.getWindowsWithTitle(current_win_title)
            if windows:
                main_win = windows[0]
                pyautogui.click(main_win.left + 10, main_win.top + 10)
            else:
                print(f"No window with title '{current_win_title}' found.")

            popup = ctk.CTk()  # Use ctk instead of tk
            popup.title("Select Expansion")

            for i, option in enumerate(key_listener_instance.expansions_list):
                raw_button_text = option['expansion'] if 'expansion' in option else "Undefined"
                button_text = truncate_text(raw_button_text, 60)
                button = ctk.CTkButton(
                    popup,
                    text=button_text,
                    command=partial(key_listener_instance.make_selection, i, popup),
                    font=("Work Sans", 12),
                    anchor="w"
                )
                button.pack(fill=ctk.X, padx=10, pady=5)

            # Update idle tasks to get updated dimensions
            popup.update_idletasks()

            # Get the content width and height
            content_width = 400
            content_height = popup.winfo_height()

              # Get the caret's screen coordinates
            caret_x, caret_y = get_caret_position()

                # Set the popup window's position to be 20 pixels below the y-coordinate of the caret
            popup.geometry(f"{content_width}x{content_height}+{caret_x}+{caret_y + 120}")

          
         
            def on_closing():
                try:
                    print("Trying to restart the listener...")  # Debugging
                    key_listener_instance.start_listener()  # Start the listener
                except Exception as e:
                    print(f"Failed to restart listener. Exception: {e}")
                finally:
                    popup.destroy()

            popup.protocol("WM_DELETE_WINDOW", on_closing)
            print("Setting WM_DELETE_WINDOW protocol")  # Debugging

            popup.attributes("-topmost", True)
            popup.focus_force()

            print("Entering Tkinter mainloop")  # Debugging
            popup.mainloop()




##############################################################
def start_app(tk_queue):
    global api  # Existing line
    api = Api()  # Existing line
    api.create_and_position_window()  # Existing line

    key_listener_instance = KeyListener(api, tk_queue)  # Moved inside start_app
    key_listener_thread = threading.Thread(target=key_listener_instance.start_listener)
    key_listener_thread.start()
    key_listener_thread.join() 

    # Pass the key_listener_instance to create_popup
    threading.Thread(target=create_popup, args=(tk_queue, key_listener_instance)).start()

    print("Starting Listener from Main.py")  # Existing line
    
    try:
        webview.start(http_server=True)
   
    finally:
        print('Cleanup function called.')
        key_listener_instance.stop_listener()
      
        
        
        time.sleep(2)
        for thread in threading.enumerate():
           print(thread.name)
             

def main():
    
    def on_close():
        # This function will be executed when the main window is closed
        root.quit()

    tk_queue = queue.Queue()  # Make sure to import the 'queue' module

    # Initialize Tkinter root window
    root = tk.Tk()
    root.withdraw()  # Hide the main Tkinter window

    root.protocol("WM_DELETE_WINDOW", on_close)  # Bind the close event to on_close function

    # Call start_app
    start_app(tk_queue)

    root.mainloop()


# Start the application
if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(f"An error occurred: {e}")
Reply


Messages In This Thread
What to do to stop all these threads? - by Valjean - Oct-01-2023, 10:38 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  stop multiple threads jeuvrey 5 3,513 Nov-15-2018, 01:34 PM
Last Post: jeuvrey

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020