Kivy screenmanager:超时后用信号切换屏幕

Kivy screenmanager: switching screen after timeout with signal

目标是在一段时间内没有按下任何按钮、输入文本或其他任何内容时移动到设置屏幕。

事实上,功能就像某种屏幕保护程序。

代码版本 1

import signal
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen


class MenuScreen(Screen):
    pass


class SettingsScreen(Screen):
    pass


class wiscApp(App):

    def setscreensaver(self, *args):
        print("switching to settings")
        # --> here I need to switch to the settings screen
        # but this doens't work, bnoth sm and setscreen are not known here
        sm.switch_to(setscreen)

    def resetscreensavertimeout(self):
        print("resetting screensaver timer")
        signal.alarm(10)  # just 5 seconds for debugging

    def build(self):
        sm = ScreenManager()
        setscreen = SettingsScreen(name='settings')
        sm.add_widget(MenuScreen(name='menu'))
        sm.add_widget(setscreen)
        signal.signal(signal.SIGALRM, self.setscreensaver)
        self.resetscreensavertimeout()
        return sm


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

和.kv

<MenuScreen>:
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            Button:
                text: "resettimeout"
                on_press: app.resetscreensavertimeout()
            Button:
                text: "do other things"
        Button:
            text: 'settings'
            on_press: root.manager.current = 'settings'

<SettingsScreen>:
    BoxLayout:
        Button:
            text: "stop app"
            on_press: app.stop()
        Button:
            text: 'Back to menu'
            on_press: root.manager.current = 'menu'

在调用 setscreensaver 函数中的 sm.switch_to(setscreen) 之前,这一直有效。

我尝试了以下方法: 代码版本 2

import signal
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen


class MenuScreen(Screen):
    pass


class SettingsScreen(Screen):
    pass


class wiscApp(App):
    sm = ScreenManager()
    setscreen = SettingsScreen(name='settings')

    def setscreensaver(self, *args):
        print("switching to settings")
        # --> here I need to switch to the settings screen
        # but this doens't work, bnoth sm and setscreen are not known here
        self.sm.switch_to(self.setscreen)

    def resetscreensavertimeout(self):
        print("resetting screensaver timer")
        signal.alarm(10)  # just 5 seconds for debugging

    def build(self):
        self.sm.add_widget(MenuScreen(name='menu'))
        self.sm.add_widget(self.setscreen)
        signal.signal(signal.SIGALRM, self.setscreensaver)
        self.resetscreensavertimeout()
        return self.sm


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

但是设置屏幕是空白的! 在代码的第一个版本中,我理解它不起作用:sm 和 setscreen 都是该函数中的未定义变量。 在第二个版本中,我不明白为什么设置屏幕是空白的。

编辑 *** 代码的版本 3***

import signal
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen


class MenuScreen(Screen):
    pass


class SettingsScreen(Screen):
    pass


class wiscApp(App):
    def setscreensaver(self, *args):
        print("switching to settings")
        # --> here I need to switch to the settings screen
        # but this doens't work, bnoth sm and setscreen are not known here
        self.sm.switch_to(self.setscreen)

    def resetscreensavertimeout(self):
        print("resetting screensaver timer")
        signal.alarm(10)  # just 5 seconds for debugging

    def build(self):
        self.sm = ScreenManager()
        self.setscreen = SettingsScreen(name='settings')
        self.sm.add_widget(MenuScreen(name='menu'))
        self.sm.add_widget(self.setscreen)
        signal.signal(signal.SIGALRM, self.setscreensaver)
        self.resetscreensavertimeout()
        return self.sm


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

在这个版本 3 中,使用信号转换到设置屏幕工作正常,但是如果我随后单击菜单按钮,我会收到此错误(此错误不会出现在其他版本的代码中):

 kivy.uix.screenmanager.ScreenManagerException: No Screen with name "menu".

所以,我有几个问题

  1. 如何在每次按下按钮时重置计时器,文本是 输入任何东西,除了为每个事件定义回调 (例如 .kv 代码中的 on_press: app.resetscreensavertimeout())?
  2. 如何在第一个版本中切换到设置屏幕 代码?
  3. 为什么代码版本 2 中的设置屏幕为空白?
  4. 为什么版本3会出现这个错误?
  5. 还有其他(更好的)编码方式吗?

非常感谢!

这是您的代码的修改版本,它使用 Clock.schedule_once() 而不是 signal:

class wiscApp(App):
    def setscreensaver(self, *args):
        print("switching to settings")
        self.resetscreensavertimeout()
        self.sm.current = 'settings'

    def resetscreensavertimeout(self, *args):
        print("resetting screensaver timer")
        self.resetEvent.cancel()
        self.resetEvent = Clock.schedule_once(self.setscreensaver, 5)

    def build(self):
        self.sm = ScreenManager()
        self.setscreen = SettingsScreen(name='settings')
        self.sm.add_widget(MenuScreen(name='menu'))
        self.sm.add_widget(self.setscreen)
        self.resetEvent = Clock.schedule_once(self.setscreensaver, 5)
        Window.bind(on_touch_down=self.resetscreensavertimeout)
        Window.bind(on_key_down=self.resetscreensavertimeout)
        return self.sm

这也使用 Window.bind() 在按下按钮或按键时触发超时重置。