Tkinter中的线程只能启动一次错误
我正在创建一个客户端网页套接字,用来连接服务器。为了通过Tkinter的按钮来启动连接,我使用了线程,这样可以避免界面卡住。但是,我发现我的客户端在连接一段时间后会断开。当我尝试再次通过按钮连接时,出现了一个错误,提示“一个线程只能启动一次”。
这是我用来创建按钮和客户端的方法的代码:
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)
我原本希望客户端能再次连接,而不会出现错误。
1 个回答
1
这个表达式创建了一个新的 Thread
对象,然后又创建并返回了一个新的 功能对象,这个对象的 __call__
方法会启动这个新线程:
threading.Thread(target=on_click).start
你可以调用这个功能对象很多次,但每次调用时,它都试图启动 同一个 线程。这是不允许的。就像错误信息所说的,一个 Thread
对象只能启动一次。
当你写 command=threading.Thread(target=on_click).start
时,你实际上是在给 Button
设置一个 command
,这个命令试图一次又一次地启动同一个线程。你需要提供一个每次都能启动新线程的 command
。
我个人认为,最简单的方法是再声明一个函数:
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
)
不过,你也可以按照 @TheLizard 在评论中说的那样做。 lambda:threading.Thread(target=on_click).start()
也是一个表达式,它返回一个新的功能对象。但不同的是,它的 __call__
方法每次都会创建一个新的 Thread
——创建并启动它。具体来说,它的 __call__
方法是这样做的:
threading.Thread(target=on_click).start()