Tkinter中的线程只能启动一次错误

0 投票
1 回答
21 浏览
提问于 2025-04-14 15:43

我正在创建一个客户端网页套接字,用来连接服务器。为了通过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()

撰写回答