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}")
