Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Python script not ending after closing TKinter GUI

Good morning,

I am trying to make a Python-Excel (via VBA) communication to display messages during VBA run time using a python TKinter GUI.

The code can exit by 2 options, 1.- Identify a "STOP" message sent from VBA or, 2.- Have received no message in a certain timeout.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I am having problems with exiting gratefully in either of the 2 options. TKinter sometimes closes, but python code is left hanging in the CMD, or in Visual Studio IDE command line, so that I don’t get prompted for a next command, just keeps living inside the script forever, which is by no means the intended functionality. Code below.

import tkinter as tk
import socket
import threading
import sys
import time
from queue import Queue

g_strSERVER = "127.0.0.1"
g_lPORT = int(sys.argv[1])
g_lTIMEOUT = 2 # As low for testing purposes only

def F_WND_CenterWindow(oWindow, lTargetWidth, lTargetHeight):
    lScreenWidth = oWindow.winfo_screenwidth()
    lScreenHeight = oWindow.winfo_screenheight()

    x = (lScreenWidth - lTargetWidth) // 2
    y = (lScreenHeight - lTargetHeight) // 2

    oWindow.geometry(f"{lTargetWidth}x{lTargetHeight}+{x}+{y}")

class clsMessageWindow:
    def __init__(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.quit_me)
        self.root.title("Log display")
        print("setting log display")

        # Set the window size (change these values as needed)
        lTargetWindowWidth = 640
        lTargetWindowHeight = 380

        # Center the window on the screen and keep it above all windows
        F_WND_CenterWindow(self.root, lTargetWidth=lTargetWindowWidth, lTargetHeight=lTargetWindowHeight)
        self.root.wm_attributes("-topmost",1)
        
        self.text_widget = tk.Text(self.root)
        self.text_widget.pack()

        self.queue = Queue()
        self.socket_thread = threading.Thread(target=self.start_socket_server)
        self.stop_flag = threading.Event()  # Event to signal the thread to stop
        self.socket_thread.start()
        print("all setup with log display")
        self.last_message_received_at = time.time()

    def start_socket_server(self):
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.bind((g_strSERVER,g_lPORT))
        server_socket.listen(1)
        print(f"Server started listening {g_strSERVER}:{g_lPORT}")

        while not self.stop_flag.is_set():  # Check the stop flag
            try:
                oClientSocket, _ = server_socket.accept()
                strMessageData = oClientSocket.recv(1024).decode("utf-8")
                arrSplitMessage = strMessageData.split('\n')
                strMessage = arrSplitMessage[-1]
                print(f"Received message: {strMessage}")

                if strMessage == "STOP":
                    print("Received STOP")
                    self.stop_flag.set()  # Set the stop flag to exit the loop
                else:
                    print(f"Adding message to queue: {strMessage}")
                    self.queue.put(strMessage)
                oClientSocket.close()
            except Exception as e:
                print(f"Error: {e}")

        # Close the server socket when done
        server_socket.close()

    def process_queue(self):
        while not self.queue.empty():
            strMessage = self.queue.get()
            self.add_message(strMessage)
            self.last_message_received_at = time.time()

        print(f"Checking if flag is set: {self.stop_flag.is_set()}")
        if not self.stop_flag.is_set():
            # Check the queue periodically if the stop flag is not set
            self.root.after(100, self.process_queue)
            current_time = time.time()
            print("Elapsed time: ", current_time - self.last_message_received_at)
            if current_time - self.last_message_received_at > g_lTIMEOUT:
                self.stop_flag.set()
                print("Over Timeout")
                self.quit_me()
        else:
            # Exit the mainloop gracefully if the stop flag is set
            self.quit_me()

    def quit_me(self):
        print("Exiting TKinter gratefully")
        self.root.quit()
        self.root.destroy()

    def add_message(self, strMessage):
        if len(strMessage) > 0:
            self.text_widget.insert(tk.END, strMessage + "\n")
            # Scroll to the end to show the message
            self.text_widget.see(tk.END)

    def run(self):
        self.process_queue()
        self.root.mainloop()

if __name__ == '__main__':
    message_window = clsMessageWindow()
    message_window.run()

Thanks

>Solution :

Your socket_thread is still working when you try to exit, which is causing the hang.

You can use a so-called daemonic thread which will be killed when your application exits. Setting this up should be as simple as:

self.socket_thread = threading.Thread(target=self.start_socket_server, daemon=True)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading