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

如何在Kivy/KivyMD中切换混合KVLang与Python定义的屏幕?

问题描述

需要实现点击按钮切换Kivy/KivyMD中同时使用KVLang和Python定义的屏幕。此前找到一篇5年前的帖子,可实现切换独立KV文件定义的屏幕,但我的场景是每个屏幕均包含分别在Python和KV文件中定义的独特元素,示例代码如下:

screen_1.py

from kivymd.app import MDApp
from kivy.lang import Builder

class Screen1(MDApp):

  def misc_func(self, *args):
    [...]

  def go_to_screen_2(self):
    """Goes to screen 2"""

  def build(self):
    return Builder.load_file("screen_1.kv")

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

screen_1.kv

MDScreen:

  FloatLayout:

    MDTopAppBar:
      title: "Screen 1"
      pos_hint: {'top': 1}

    MDRaisedButton:
      text: "misc func"
      on_press: app.misc_func()
      pos_hint: {'center_x': 0.5, 'center_y': 0.6}

    MDRaisedButton:
      text: "go to screen 2"
      pos_hint: {'center_x': 0.5, 'center_y': 0.4}
      on_press: app.go_to_screen_2()

screen_2.py

from kivymd.app import MDApp
from kivy.lang import Builder

class Screen2(MDApp):

  def go_to_screen_1(self):
    """Goes to screen 1"""

  def a_different_misc_func(self, *args):
    [...]

  def build(self):
    return Builder.load_file("screen_2.kv")

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

screen_2.kv

MDScreen:

  FloatLayout:

    MDTopAppBar:
      title: "Screen 2"
      pos_hint: {'top': 1}

    MDRaisedButton:
      text: "misc func"
      on_press: app.a_different_misc_func()
      pos_hint: {'center_x': 0.5, 'center_y': 0.6}

    MDRaisedButton:
      text: "go to screen 1"
      pos_hint: {'center_x': 0.5, 'center_y': 0.4}
      on_press: app.go_to_screen_1()

解决方案

你的核心问题是错误地将每个屏幕定义为独立的MDApp实例。Kivy/KivyMD的屏幕切换逻辑必须基于ScreenManager管理多个MDScreen实例,而非创建多个App。以下是重构后的实现方案:

1. 重构屏幕类

将Screen1和Screen2从MDApp子类改为MDScreen子类,保留各自的业务逻辑:

screen_1.py

from kivymd.uix.screen import MDScreen
from kivy.lang import Builder

class Screen1(MDScreen):
    def misc_func(self, *args):
        # 自定义逻辑示例
        print("执行Screen1的misc_func")

    def go_to_screen_2(self):
        """切换到Screen2"""
        self.manager.current = "screen2"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Builder.load_file("screen_1.kv")

screen_2.py

from kivymd.uix.screen import MDScreen
from kivy.lang import Builder

class Screen2(MDScreen):
    def a_different_misc_func(self, *args):
        # 自定义逻辑示例
        print("执行Screen2的a_different_misc_func")

    def go_to_screen_1(self):
        """切换到Screen1"""
        self.manager.current = "screen1"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Builder.load_file("screen_2.kv")

2. 修改KV文件

调整KV文件的根节点为对应屏幕类的规则布局,无需再定义MDScreen根节点:

screen_1.kv

<Screen1>:
    FloatLayout:
        MDTopAppBar:
            title: "Screen 1"
            pos_hint: {'top': 1}

        MDRaisedButton:
            text: "misc func"
            on_press: root.misc_func()
            pos_hint: {'center_x': 0.5, 'center_y': 0.6}

        MDRaisedButton:
            text: "go to screen 2"
            pos_hint: {'center_x': 0.5, 'center_y': 0.4}
            on_press: root.go_to_screen_2()

screen_2.kv

<Screen2>:
    FloatLayout:
        MDTopAppBar:
            title: "Screen 2"
            pos_hint: {'top': 1}

        MDRaisedButton:
            text: "misc func"
            on_press: root.a_different_misc_func()
            pos_hint: {'center_x': 0.5, 'center_y': 0.6}

        MDRaisedButton:
            text: "go to screen 1"
            pos_hint: {'center_x': 0.5, 'center_y': 0.4}
            on_press: root.go_to_screen_1()

3. 主App入口

编写统一的主App类,使用ScreenManager管理所有屏幕:

main.py

from kivymd.app import MDApp
from kivymd.uix.screenmanager import MDScreenManager
from screen_1 import Screen1
from screen_2 import Screen2

class MainApp(MDApp):
    def build(self):
        sm = MDScreenManager()
        # 添加屏幕并设置唯一标识
        sm.add_widget(Screen1(name="screen1"))
        sm.add_widget(Screen2(name="screen2"))
        # 设置初始显示屏幕
        sm.current = "screen1"
        return sm

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

关键说明

  • 所有屏幕必须是MDScreen(或Screen)子类,才能被ScreenManager统一管理。
  • 通过self.manager.current切换屏幕,manager是每个屏幕自带的属性,指向所属的ScreenManager。
  • KV文件中用<Screen1>:类规则绑定Python类,布局会自动应用到对应屏幕实例。
  • 主App仅初始化一次ScreenManager,所有屏幕切换逻辑由其统一调度。

内容的提问来源于stack exchange,提问作者Zach M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:09:54