You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何执行while循环后Tkinter窗口仍关闭?已调用quit和update

问题描述

我使用Python的socket和tkinter库开发一款双人连接应用,目前遇到的问题是无法让Tkinter窗口按预期消失(下一步计划实现双人聊天窗口)。我已将相关逻辑放在线程中,主进程运行mainloop,即使在socket的while循环前调用了window.quit()和window.update(),循环结束后窗口仍会关闭。目前暂时不关注窗口冻结问题。

主函数代码

from tkinter import *
import threading
from hosting import getHostAddress, getConnected
from client import connectToHost
 
def hostServer():
    hostB.destroy()
    connectB.destroy()
    e.destroy()

    addr, sock = getHostAddress()
    hostingText = addr + "\nWaiting for Connection"

    hostLabel = Label(window, text=hostingText)
    hostLabel.pack()

    getConnected(sock, window)

def connectToIP():
    IP = e.get()
    window.destroy()
    connectToHost(IP)

def connectServer():
    hostB.destroy()
    connectB.destroy()

    conLabel = Label(window, text="Enter Code")
    conLabel.pack(side="left")
    e.pack(side="left")
    window.geometry("250x50")
    conButton = Button(window, text="Connect", command=connectToIP)
    conButton.pack(side="left")

if __name__ =="__main__":
    window = Tk()
    
    e = Entry(window)
    hostB = Button(window, text="Host", command=threading.Thread(target=hostServer).start)
    hostB.pack()
    connectB = Button(window, text="Connect", command=connectServer)
    connectB.pack()

    window.mainloop()

client.py

import socket

port = 5000;
client = socket.socket()

def connectToHost(IPAddr):
  client.connect((IPAddr, port))

  message = input(" -> ")  # take input

  while message.lower().strip() != 'bye':
    client.send(message.encode())  # send message
    data = client.recv(1024).decode()  # receive response

    print('Received from server: ' + data)  # show in terminal

    message = input(" -> ")  # again take input

  client.close()  # close the connection

hosting.py

import socket

#def getPort():

def getHostAddress():
  hostname = socket.gethostname()
  IPAddr = socket.gethostbyname(hostname)

  sock = socket.socket()
  sock.bind((hostname, 5000))

  addr = IPAddr

  return addr, sock

def getConnected(sock, window):
  sock.listen(2)
  conn, address = sock.accept()  # accept new connection

  window.quit()
  window.update()

  while True:
    # receive data stream. it won't accept data packet greater than 1024 bytes
    data = conn.recv(1024).decode()
    if not data:
      # if data is not received break
      break
    print("from connected user: " + str(data))
    data = input(' -> ')
    conn.send(data.encode())  # send data to the client

  conn.close()  # close the connection
解决方案

核心问题

window.quit()仅终止Tkinter的mainloop(),但不会销毁窗口对象。主线程退出mainloop()后,程序仍会等待子线程中的socket循环结束,此时窗口处于无主循环管理的状态,等线程结束程序退出时窗口才会关闭。

修改方案

  1. 替换窗口关闭方式:在hosting.py的getConnected函数中,用window.destroy()替代window.quit()和window.update(),直接销毁窗口:
def getConnected(sock, window):
  sock.listen(2)
  conn, address = sock.accept()  # accept new connection

  # 直接销毁窗口,而非终止主循环
  window.destroy()

  while True:
    data = conn.recv(1024).decode()
    if not data:
      break
    print("from connected user: " + str(data))
    data = input(' -> ')
    conn.send(data.encode())

  conn.close()
  1. 修复线程启动隐患:主函数中按钮的command参数直接调用start()会导致线程提前执行,改用lambda包裹确保点击时才启动线程:
hostB = Button(window, text="Host", command=lambda: threading.Thread(target=hostServer).start())

修改后,连接建立时窗口会立即销毁,无需等待socket循环结束。

内容的提问来源于stack exchange,提问作者Noah McBride

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:25:15