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

Kivy中Screen Manager无法通过按钮导航至新页面求助

Kivy多屏幕导航失败问题

我在Kivy中使用多屏幕架构,在名为Riddles的Screen内包含一个带有按钮的Riddlepage布局。尝试通过点击这些按钮,调用MainApp中定义的navigate函数跳转到Page2页面,绑定代码为b.bind(on_press=lambda x:MainApp().navigate("Page2")),但点击按钮后Screen Manager无法完成导航。

以下是部分代码:

class Page2(Screen):
    name="Page2"
class Riddles(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
class Riddlepage(BoxLayout):
    def __init__(self, **kwargs):
        self.pp = open("riddle.txt", "r")
        super().__init__(**kwargs)
        self.orientation = "vertical"
        self.spacing = dp(5)
        self.pos_hint = {"top": 1}
        for line in self.pp.readlines():
            b = Button(text=line, size_hint=(.8, None), pos_hint={"x": .1}, height=(dp(40)),background_color=(0,0,1))
            b.bind(on_press=lambda x:MainApp().navigate("Page2"))
            self.add_widget(b)
        self.pp.close()
class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        with open("profile.txt", "r", encoding="utf-8") as file:
            self.info = file.readlines()
        self.sm=ScreenManager()
    def build(self):
        self.sm.add_widget(Page1(name="Page1"))
        self.sm.add_widget(Riddles(name="Riddles"))
        self.sm.add_widget(Coursewindow(name="Coursewindow"))
        self.sm.add_widget(Ancienwindow(name="Ancienwindow"))
        self.sm.add_widget(Level(name="Level"))
        self.sm.add_widget(Levels(name="Levels"))
        self.sm.add_widget(Corrections(name="Corrections"))
        self.sm.add_widget(Past_papers(name="Past_papers"))
        self.sm.add_widget(Page2(name="Page2"))
        self.sm.add_widget(Page3(name="Page3"))
        self.sm.add_widget(Profile(name="Profile"))
        return self.sm
    def navigate(self,p):
        self.sm.add_widget(Page2())
        self.sm.current="Page2"
        return self.sm
MainApp().run()

问题根源

  1. 错误创建新的MainApp实例:MainApp()在lambda中会生成一个全新的App实例,而非引用当前正在运行的实例。这个新实例的ScreenManager和界面上实际使用的完全无关,调用它的navigate函数自然无法影响当前界面导航。
  2. 重复添加Page2屏幕:navigate函数里每次都调用self.sm.add_widget(Page2()),但build方法中已经添加过Page2(name="Page2"),重复添加会导致ScreenManager中存在多个同名屏幕,可能引发逻辑冲突。

修复方案

1. 获取当前运行的App实例

修改按钮绑定代码,使用App.get_running_app()获取当前正在运行的MainApp实例,而非创建新实例:

# 确保导入App类
from kivy.app import App

# 在Riddlepage的__init__方法中修改绑定逻辑
b.bind(on_press=lambda x: App.get_running_app().navigate("Page2"))

2. 优化navigate函数

移除重复添加Page2的代码,直接切换到已存在的屏幕:

def navigate(self,p):
    self.sm.current = p  # 直接使用传入的参数,无需硬编码页面名称
    return self.sm

3. 完整修改后的Riddlepage类

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.metrics import dp

class Riddlepage(BoxLayout):
    def __init__(self, **kwargs):
        # 使用with语句管理文件资源,避免泄漏
        with open("riddle.txt", "r") as self.pp:
            super().__init__(**kwargs)
            self.orientation = "vertical"
            self.spacing = dp(5)
            self.pos_hint = {"top": 1}
            for line in self.pp.readlines():
                b = Button(text=line, size_hint=(.8, None), pos_hint={"x": .1}, height=(dp(40)), background_color=(0,0,1))
                b.bind(on_press=lambda x: App.get_running_app().navigate("Page2"))
                self.add_widget(b)

额外补充

确保Riddles屏幕正确添加Riddlepage布局:

class Riddles(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.add_widget(Riddlepage())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 11:49:58