【问题标题】:Kivy ScreenManager switching "Start" screen on a conditionKivy ScreenManager 在条件下切换“开始”屏幕
【发布时间】:2020-05-19 14:45:55
【问题描述】:

我是 kivy 的新手,想开始一个小应用项目。我想要达到的目标:

  • 当您第一次启动应用程序时 -> 显示带有某种用户数据表单的屏幕
  • 将数据存储在 JsonStore -> 转到主屏幕
  • 下次运行应用程序->检查userdata是否在JsonStore中并直接进入主屏幕

到目前为止,我已经找到了一个可行的解决方案,但它的工作方式让我并不满意。我想要的是在 .kv 文件中创建 ScreenManager 和 Screens 并让 .py 文件执行逻辑(通过检查存储中是否存在用户数据来加载哪个屏幕)。

我试过了:

  • 使用 ScreenManager 类 (def __init__) - 无效
  • 从 .kv 文件中调用方法,如下所示(也不起作用):
<WindowManager>:
    root.check_for_user()
    MainWindow:
    UserDataWindow:
<MainWindow>:
...

到目前为止,这是我的工作代码:

main.py:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.storage.jsonstore import JsonStore

class LoginWindow(Screen):
    nick = ObjectProperty(None)
    isle = ObjectProperty(None)
    hemisphere_n = ObjectProperty(None)
    hemisphere_s = ObjectProperty(None)

    def submit(self):
        store = JsonStore('store.json')
        if self.hemisphere_n.state == 'down' and self.hemisphere_s.state == 'normal':
            store.put('user', nickname=self.nick.text, island=self.isle.text, hemisphere="north")
        elif self.hemisphere_n.state == "normal" and self.hemisphere_s.state == "down":
            store.put('user', nickname=self.nick.text, island=self.isle.text, hemisphere="south")

class MainWindow(Screen):
    pass        

class WindowManager(ScreenManager):
    pass

kv = Builder.load_file("my.kv")
sm = WindowManager()
store = JsonStore('store.json')
screens = [MainWindow(name="main"), LoginWindow(name="login")]

for screen in screens:
    sm.add_widget(screen)

if store.exists('user'):
    print("exists")
    sm.current = "main"
else:
    print("not found")
    sm.current = "login"

class MainApp(App):
    def build(self):
        return sm

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

我的.kv:

#:kivy 1.11.1

<MainWindow>:
    FloatLayout:
        Label:
            text:
        Button:
            text: "Go Back"
            pos_hint: {"x": 0.45, "top": 0.5}
            size_hint: (0.1, 0.05)
            on_release:
                app.root.current = "login"

<LoginWindow>:
    nick: nickname
    isle: island
    hemisphere_n: hemisphere_n
    hemisphere_s: hemisphere_s
    FloatLayout:
        Label:
            text: "Nickname:"
            pos_hint: {"x": 0.45, "top": 0.7}
            size_hint: (0.1, 0.05)
        TextInput:
            id: nickname
            multiline: False
            pos_hint: {"x": 0.4, "top": 0.65}
            size_hint: (0.2, 0.05)

        Label:
            text: "Island Name:"
            pos_hint: {"x": 0.45, "top": 0.6}
            size_hint: (0.1, 0.05)
        TextInput:
            id: island
            multiline: False
            pos_hint: {"x": 0.4, "top": 0.55}
            size_hint: (0.2, 0.05)
        Label:
            text: "Hemisphere:"
            pos_hint: {"x": 0.45, "top": 0.5}
            size_hint: (0.1, 0.05)
        ToggleButton:
            id: hemisphere_n
            text: "North"
            group: "hemisphere"
            state: "down"
            pos_hint: {"x": 0.41, "top": 0.45}
            size_hint: (0.08, 0.05)
        ToggleButton:
            id: hemisphere_s
            text: "South"
            group: "hemisphere"
            pos_hint: {"x": 0.51, "top": 0.45}
            size_hint: (0.08, 0.05)
        Button:
            text: "Submit"
            pos_hint: {"x": 0.45, "top": 0.38}
            size_hint: (0.1, 0.05)
            on_press:
                root.submit()
            on_release:
                app.root.current = "main"

请忽略某些地方的松散端。在继续之前,我想先完成这项工作。 它现在进入主屏幕(当我将屏幕添加到屏幕管理器时),然后检查用户数据并最终切换到登录。你有什么建议吗? 提前致谢。

【问题讨论】:

  • 你说它有效,但它并不让你满意。究竟是什么不愉快?
  • 它现在的工作方式:进入主屏幕 -> 然后检查是否存储了用户数据 -> 如果不进入用户表单/登录屏幕。是否没有一个选项可以预先检查用户数据,然后根据返回转到主屏幕或用户数据屏幕?从主屏幕到登录屏幕的第一次切换实际上是可见的......

标签: python android python-3.x kivy


【解决方案1】:

您几乎可以将Screen 选择逻辑放在您想要的任何位置。这是将其放入 WindowManager 类的示例:

class WindowManager(ScreenManager):
    def select_start_screen(self):
        store = JsonStore('store.json')

        self.transition = NoTransition()
        if store.exists('user'):
            print("exists")
            self.current = "main"
        else:
            print("not found")
            self.current = "login"
        self.transition = SlideTransition()

然后你可以在你的build()方法中调用select_start_screen()

class MainApp(App):
    def build(self):
        sm.select_start_screen()
        return sm

【讨论】:

    【解决方案2】:

    您看到的是transition 动画。您可以像这样使用NoTransition() 来消除这种情况:

    sm.transition = NoTransition()
    if store.exists('user'):
        print("exists")
        sm.current = "main"
    else:
        print("not found")
        sm.current = "login"
    sm.transition = SlideTransition()
    

    【讨论】:

    • 好的,这将消除可见的过渡,但它不会改变它的工作方式或给屏幕管理器某种逻辑来实际决定哪个屏幕适合显示。如果它不能以任何其他方式工作,我会将此解决方案与@Nattosai 的空白屏幕结合使用。
    • 我认为 if else 是逻辑。是否有其他逻辑来决定显示哪个Screen
    • 是的,这就是我放在那里的逻辑。但我正在寻找一种可能性,让该逻辑在屏幕管理器本身中运行,以便屏幕管理器能够决定首先显示哪个屏幕。如下所示: Screenmanager -> 检查用户数据 -> 如果存在则显示主屏幕 -> 如果不显示登录屏幕
    【解决方案3】:

    在@John 的回答中先添加一个空白屏幕怎么样。

    sm.add_widget(Screen(name='blank'))
    for screen in screens:
        sm.add_widget(screen)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      • 2021-10-06
      相关资源
      最近更新 更多