使用socket的client.recv()接收数据时Kivy UI崩溃问题咨询
问题根因
- 你当前的写法存在两处核心错误:
- 把
client.recv()直接定义为MenuScreen的类属性,Kivy加载所有页面时就会立即执行这行代码,此时还没有发送登录请求,recv()作为阻塞IO方法会一直卡住等待数据,直接冻结UI线程。 MenuScreen类内直接写return data属于语法错误,不符合Python类定义规则。
- 所有GUI框架的UI操作都运行在主线程,任何阻塞主线程的操作(包括阻塞式socket收发、耗时计算)都会直接导致界面无响应,不是Kivy没有socket接收方案,而是不能把阻塞操作放到主线程执行。
快速修复方案(适配你临近截止的需求,修改量极小)
第一步:修改kv代码中MenuScreen的欢迎Label,增加id方便更新
找到MenuScreen下的这段Label定义:
MDLabel: id: welcome_name # 新增这行id text: '' font_style: 'H2' font_size: 50 halign: 'center' pos_hint: {'center_y': 0.36}
第二步:重写MenuScreen类代码,把接收逻辑放到子线程执行
class MenuScreen(Screen): # 删掉原来错误的两行代码,改成下面的逻辑 def on_enter(self, *args): # 进入菜单页时才启动子线程接收数据,不会阻塞UI start_new_thread(self.receive_user_data, ()) def receive_user_data(self): # 子线程执行阻塞recv操作 data = pickle.loads(client.recv(1024)) # Kivy UI更新必须在主线程执行,用Clock调度 Clock.schedule_once(lambda dt: self.update_welcome_text(data)) def update_welcome_text(self, first_name): self.ids.welcome_name.text = first_name
第三步:修正服务端返回逻辑(可选,匹配你返回first_name的需求)
你当前服务端display函数返回的是用户名info[1],如果需要返回用户的first_name,修改查询逻辑即可:
def display(client, info): try: # 改查询语句,匹配用户名密码后取firstname字段 query = "SELECT firstname FROM users WHERE username = %s AND password = %s" mycur.execute(query, (info[1], info[2])) rs = mycur.fetchone() if rs: client.send(pickle.dumps(rs[0])) else: client.send(pickle.dumps("登录失败")) except Exception as e: print(e)
额外优化建议
可以把登录按钮的跳转逻辑改成校验成功再跳转,避免用户看到加载中的空白名字:
- 登录请求发送后不要立即切页,子线程收到服务端返回的登录结果后,再调用
root.manager.current = 'menu',同时把用户名传递给菜单页即可。
内容的提问来源于stack exchange,提问作者Falah
相关产品推荐
相关产品推荐

