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)
I was expecting that client connects again without errors
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()