EN VI

Python - Thread can only be started once error in Tkinter?

2024-03-16 01:00:06
Python - Thread can only be started once error in Tkinter

I am creating a client web socket that connects to a server. And I am starting the connection using a Tkinter gui button. To prevent gui from getting stuck I am using threading. My client disconnects from the server after some time. So when I try to connect again using the button it shows an error that a Thread can only be started once.

My code for Button and client method:

async def start_client(url, duration):
    async with websockets.connect(url) as ws:
        start_time = time.time()
        while time.time() - start_time < duration:
            message = await ws.recv()
            msg = json.loads(message)
            print(msg)

            if 'timestamp android.sensor.accelerometer' in msg:
                write_acc(msg)
            else:
                write_gyro(msg)



def on_click():
    initial_setup_files()
    asyncio.run(start_client(url, 4))
    final_csv_file_creator()
    print("Disconnected from the server")




btn = Button(window,
             text="Start Server ",
             fg="black",
             bg="cyan",
             font=("Times New Roman", 30, 'bold'),
             command=threading.Thread(target=on_click).start
             )
btn.pack(padx=20,
         pady=20)

Error

I was expecting that client connects again without errors

Solution:

This expression creates a new Thread object, and then it creates and returns a new functional object whose __call__ method starts the new thread:

threading.Thread(target=on_click).start

You can call the functional object any number of times, but every time you call it, it tries to start the same thread. That's not allowed. It's just like the error message says. A Thread object may only be started one time.

When you said, command=threading.Thread(target=on_click).start, you're giving the Button a command that tries to start the same thread again and again. You need to provide a command that starts a new thread every time.

The most obvious way (in my personal opinion) is to declare another function:

def handle_button_press():
    threading.Thread(target=on_click).start()

btn = Button(window,
             text="Start Server ",
             fg="black",
             bg="cyan",
             font=("Times New Roman", 30, 'bold'),
             command=handle_button_press
             )

But, you can also do what @TheLizard said in a comment. lambda:threading.Thread(target=on_click).start() also is an expression that returns a new functional object. But, the difference is, its __call__ method creates a new Thread every time—creates and then starts it. Specifically, it's __call__ method does this:

threading.Thread(target=on_click).start()
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login