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

如何修复Kivy Python程序中的‘Screen already managed by another ScreenManager’错误

Kivy拆分代码后Screen already managed by another ScreenManager异常修复方案

问题背景

为提升代码可维护性,将Python Kivy游戏代码拆分到多个文件后,程序运行抛出Screen already managed by another ScreenManager异常。已知存在循环导入问题,但不愿通过合并代码解决。

错误原因

  1. 循环导入触发重复实例化:login_screen.py的login()方法中导入main.py的languagechanapp,而main.py启动时已导入login_screen.py的loginscreen,导致登录成功时LanguageChanApp被再次实例化,loginscreen被重复添加到新的ScreenManager。
  2. 全局实例导致重复关联:login_screen.py中定义了全局的loginscreen、loginwin、regwin实例,这些实例会被多次引用,同一个Screen实例被尝试添加到多个ScreenManager。

修复步骤

  • 移除模块级别的全局实例,改为在类内部按需创建布局实例
  • 使用App.get_running_app()获取当前运行的App实例,替代循环导入
  • 调整屏幕切换逻辑,通过App实例直接操作ScreenManager
  • 确保每个Screen实例仅被添加到一个ScreenManager

修改后的代码示例

main.py

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager

from login_screen import LoginScreen
from game_screen import GameScreen  # 对应原gamescreen类
from quiz_screen import QuizScreen  # 对应原quizscreen类


class LanguageChanApp(App):
    def build(self):
        self.screen_manager = ScreenManager()
        # 实例化各个屏幕,而非导入全局实例
        self.screen_manager.add_widget(LoginScreen(name="Login Screen"))
        self.screen_manager.add_widget(GameScreen(name="Game Screen"))
        self.screen_manager.add_widget(QuizScreen(name="Quiz Screen"))
        
        return self.screen_manager

    def goto_loginscreen(self):
        self.screen_manager.current = "Login Screen"

    def goto_gamescreen(self):
        self.screen_manager.current = "Game Screen"

    def goto_quizscreen(self):
        self.screen_manager.current = "Quiz Screen"


if __name__ == "__main__":
    LanguageChanApp().run()

login_screen.py

from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.app import App

from db_interface import userDBinter


Builder.load_file('login_screen_GUI.kv')

class LoginWin(GridLayout):
    def login(self):
        if self.ids.nickname.text == '' or self.ids.password.text == '':
            return
        usernum = userDBinter.selectUsernum(self.ids.nickname.text, self.ids.password.text)
        if usernum is None:
            Popup(title="Login Error", content=Label(text="Sorry, we can't find your account :("), size_hint=(1, 0.2), auto_dismiss=True).open()
        else:
            # 通过App.get_running_app()获取当前App实例,避免循环导入
            app = App.get_running_app()
            app.goto_gamescreen()

    def showRegwin(self):
        # 获取当前所在的LoginScreen实例
        screen = self.parent
        screen.exchangeToRegwin()

class RegWin(GridLayout):
    def register(self):
        if self.ids.nickname.text == '' or self.ids.mailaddr.text == '' or self.ids.password.text == '':
            return
        if self.ids.password.text != self.ids.pwagain.text:
            Popup(title="Password Error", content=Label(text="Please write same password!!"), size_hint=(1, 0.2), auto_dismiss=True).open()
            return
        result = userDBinter.insertUserInfo(self.ids.nickname.text, self.ids.mailaddr.text, self.ids.password.text)
        if result:
            Popup(title="Congrats!", content=Label(text="Registration succeeded!"), size_hint=(1, 0.2), auto_dismiss=True).open()
        else:
            Popup(title="Registration Error", content=Label(text="Sorry, your registration is failed :("), size_hint=(1, 0.2), auto_dismiss=True).open()

    def showLoginwin(self):
        screen = self.parent
        screen.exchangeToLoginwin()

class LoginScreen(Screen):
    def __init__(self, **kwargs):
        super(LoginScreen, self).__init__(**kwargs)
        # 在类内部创建布局实例,避免全局复用
        self.loginwin = LoginWin()
        self.regwin = RegWin()

    def showLoginwin(self):
        self.add_widget(self.loginwin)

    def exchangeToLoginwin(self):
        if self.regwin in self.children:
            self.remove_widget(self.regwin)
        self.add_widget(self.loginwin)

    def exchangeToRegwin(self):
        if self.loginwin in self.children:
            self.remove_widget(self.loginwin)
        self.add_widget(self.regwin)

login_screen_GUI.kv

<LoginWin>
    cols: 2
    size_hint: 1, 0.2
    Label:
        text: "Nickname:"
        width: 100
        color: "black"
    TextInput:
        id: nickname
    Label:
        text: "Password:"
        width: 100
        color: "black"
    TextInput:
        id: password
    Button:
        id: loginbutton
        text: "Login"
        on_release: root.login()
    Button:
        id: regbutton
        text: "Register"
        on_release: root.showRegwin()

<RegWin>
    cols: 2
    size_hint: 1, 0.4
    Label:
        text: "Make nickname:"
        width: 100
        color: "black"
    TextInput:
        id: nickname
    Label:
        text: "Input mail address:"
        width: 100
        color: "black"
    TextInput:
        id: mailaddr
    Label:
        text: "Set password:"
        width: 100
        color: "black"
    TextInput:
        id: password
    Label:
        text: "Password again?"
        width: 100
        color: "black"
    TextInput:
        id: pwagain
    Button:
        id: regbutton
        text: "Register me!"
        on_release: root.register()
    Button:
        id: exitButton
        text: "Exit"
        on_release: root.showLoginwin()

<LoginScreen>
    Button:
        pos_hint: {"anchor_x":"center", "anchor_y":"center"}
        size_hint: 1, 1
        background_normal: "graphics\\title_image.jpg"
        on_press: root.showLoginwin()

内容的提问来源于stack exchange,提问作者이지응

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:34:53