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

PyQt5聊天室项目中setText()调用致窗口冻结问题咨询

问题分析

你的问题核心在于UI线程被阻塞了。PyQt的所有UI操作必须在主线程(也就是Qt的事件循环线程)中执行,而你的createServer方法里调用了self.Listen(),这个方法里有一个while self.shutting == False的循环,会一直占用主线程,导致Qt的事件循环无法处理UI更新请求——所以display.setText()/append()的操作没法生效,窗口也会冻结。而except块里的操作能正常工作,是因为异常发生时,代码还没进入那个阻塞的循环,主线程还能处理UI更新。

解决方案

要解决这个问题,你需要把阻塞的监听逻辑放到子线程中执行,同时子线程不能直接操作UI组件,得通过Qt的信号-槽机制来通知主线程更新UI。

步骤1:定义信号类

首先创建一个继承自QObject的信号类,用来传递需要显示的文本:

from PyQt5.QtCore import QObject, pyqtSignal

class ServerSignals(QObject):
    update_display = pyqtSignal(str)

步骤2:修改sWindow类,添加信号实例

在sWindow的__init__方法里初始化这个信号实例,并连接到display的append方法:

def __init__(self, title = "File Sharing", l = 0, t = 0, r = 800, b = 600):
    super().__init__()
    # ... 保留原有初始化代码 ...
    self.signals = ServerSignals()
    # 连接信号到display的append方法,实现UI更新
    self.signals.update_display.connect(self.display.append)

步骤3:重构createServer和Listen方法

把Listen里的阻塞逻辑放到子线程中,并且在需要更新UI的地方发送信号,而不是直接调用display的方法:

def createServer(self):
    try:
        # 这里可以直接操作UI,因为还没进入阻塞逻辑
        self.display.setText("Creating server")
        print("Creating Server")
        self.s.bind((self.host, self.port))
        self.s.listen(10)
        print("Server Created")
        # 用信号通知主线程更新UI
        self.signals.update_display.emit("Server Created.")
        self.signals.update_display.emit("Started listening to clients")
        # 启动子线程执行监听逻辑,daemon=True确保主线程退出时子线程自动结束
        threading.Thread(target=self.Listen, daemon=True).start()
    except Exception as e:
        print(e)
        self.display.setText("Error occured")

def Listen(self):
    try:
        print("started listening")
        while not self.shutting:
            client, addr = self.s.accept()
            self.address[client] = addr
            message = "Enter your name: "
            client.send(message.encode(self.encoding))
            # 启动子线程处理单个客户端,注意传递addr参数
            threading.Thread(target=self.handleclient, args=(client, addr,), daemon=True).start()
    except Exception as e:
        print('Error occured while creating server. ',e)
        # 发送错误信息到UI
        self.signals.update_display.emit(f"Error while creating server: {str(e)}")

步骤4:修复handleclient和broadcast方法里的错误

你的代码里还有几个小问题需要修正:

  • handleclient方法里的buffsize和encoding应该用self.buffsize和self.encoding,并且需要接收addr参数
  • broadcast方法里的参数拼写错误mesage→message,发送时需要统一编码格式

修正后的代码:

def handleclient(self, client, addr):
    try:
        name = client.recv(self.buffsize).decode(self.encoding)
        # 用信号更新UI
        self.signals.update_display.emit(f"{name} connected from address {addr}")
        self.clientaddr[client] = name
        message = f"Welcome {name}!! You have entered the chatroom."
        client.send(message.encode(self.encoding))
        broadcast_msg = f"{name} has entered the chatroom. "
        self.broadcast(broadcast_msg, client)
        while not self.shutting:
            data = client.recv(self.buffsize).decode(self.encoding)
            self.signals.update_display.emit(f"{name}: {data}")
            self.broadcast(f"{name}: {data}", client)
    except Exception as e:
        del self.address[client]
        if client in self.clientaddr:
            del self.clientaddr[client]
        self.signals.update_display.emit(f'Error while connecting to client: {str(e)}')
        broadcast_msg = f"{name} left the chatroom."
        self.broadcast(broadcast_msg.encode(self.encoding), False)
        return

def broadcast(self, message, client):
    try:
        # 统一处理字符串编码
        if isinstance(message, str):
            message = message.encode(self.encoding)
        for sock in self.address.keys():
            if sock != client:
                sock.send(message)
    except Exception as e:
        self.signals.update_display.emit(f"Error while broadcasting message: {str(e)}")
        print(e)
        return
关键知识点
  1. UI线程不能阻塞:PyQt的事件循环在主线程,任何阻塞主线程的操作(比如无限循环、长时间IO)都会导致UI冻结,必须把这些操作放到子线程。
  2. 子线程不能直接操作UI:Qt规定只有主线程能操作UI组件,子线程需要通过信号-槽机制来通知主线程更新UI,这是线程安全的方式。
  3. 守护线程:使用daemon=True创建线程,这样当主线程退出时,子线程会自动结束,避免残留后台线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:40:04