Oct-01-2023, 10:38 PM
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.
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}")