Kivy ScreenManager无法显示首个屏幕问题求助
问题原因及解决方案
核心问题在于:Kivy的Screen类没有build方法。当你将Login改为继承App时,build方法会被App的run()自动调用;但当Login作为Screen被添加到ScreenManager时,这个方法不会被执行,导致你创建的布局根本没有被添加到屏幕中,所以出现空白窗口。
修复方案一:修改Login类的初始化逻辑
将原有的build方法替换为__init__方法,同时完成父类初始化和布局添加:
from kivy.uix.screenmanager import Screen from kivy.uix.gridlayout import GridLayout from kivy.uix.image import Image from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.uix.button import Button import json class Login(Screen): def __init__(self, **kwargs): super().__init__(**kwargs) # 必须调用父类初始化方法,保证Screen正常工作 self.window = GridLayout() self.window.cols = 1 self.window.size_hint = (0.6, 0.7) self.window.pos_hint = {"center_x": 0.5, "center_y": 0.5} self.window.add_widget(Image( source="logo.png", size_hint=(10, 10) )) self.username = Label( text="Username", font_size=50, bold=True ) self.window.add_widget(self.username) self.userinp = TextInput( multiline=False, padding_y=(20, 20), size_hint=(1, 0.8) ) self.window.add_widget(self.userinp) self.password = Label( text="Password", font_size=50, bold=True ) self.window.add_widget(self.password) self.passwordinp = TextInput( multiline=False, size_hint=(1, 0.8) ) self.window.add_widget(self.passwordinp) self.login = Button( text="Login", size_hint=(1, 0.8), bold=True ) self.login.bind(on_press=self.callback) self.window.add_widget(self.login) self.add_widget(self.window) # 将布局添加到Screen自身 def callback(self, instance): print("button pressed") username = self.userinp.text password = self.passwordinp.text try: with open('passwords.json') as f: data = json.load(f) except FileNotFoundError: print("Error") return if username not in data: print('User not found') return elif data[username] != password: self.login.text = 'Incorrect password' return else: self.login.text = 'Login successful' self.cusername = username self.manager.current = "Home" # 替换原错误的root.manager,使用Screen自身的manager属性
修复方案二:使用Kv语言定义布局(推荐)
这是Kivy官方推荐的方式,将布局与逻辑分离,代码更清晰:
from kivy.app import App from kivy.uix.screenmanager import Screen, ScreenManager from kivy.lang import Builder import json # 内嵌Kv布局代码 Builder.load_string(''' <Login>: GridLayout: cols: 1 size_hint: 0.6, 0.7 pos_hint: {"center_x": 0.5, "center_y": 0.5} Image: source: "logo.png" size_hint: 10, 10 Label: text: "Username" font_size: 50 bold: True TextInput: id: userinp multiline: False padding_y: 20, 20 size_hint: 1, 0.8 Label: text: "Password" font_size: 50 bold: True TextInput: id: passwordinp multiline: False size_hint: 1, 0.8 Button: id: login_btn text: "Login" size_hint: 1, 0.8 bold: True on_press: root.callback(self) ''') class Login(Screen): def callback(self, instance): print("button pressed") username = self.ids.userinp.text password = self.ids.passwordinp.text try: with open('passwords.json') as f: data = json.load(f) except FileNotFoundError: print("Error") return if username not in data: print('User not found') return elif data[username] != password: self.ids.login_btn.text = 'Incorrect password' return else: self.ids.login_btn.text = 'Login successful' self.cusername = username self.manager.current = "Home" class AppManager(App): def build(self): sm = ScreenManager() sm.add_widget(Login(name = "Login")) # sm.add_widget(home(name = "Home")) sm.current = "Login" return sm if __name__ == '__main__': AppManager().run()
额外注意点
- 必须调用
super().__init__(**kwargs):否则Screen的核心功能无法正常初始化 - 回调中的
root.manager需改为self.manager:在Screen类中,self.manager直接指向所属的ScreenManager - 若使用Kv语言,可通过
self.ids访问布局中的控件,无需在Python代码中手动创建实例
内容的提问来源于stack exchange,提问作者Charlie
相关产品推荐
相关产品推荐

