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

时间:2021-01-21 07:59:04

标签: python kivy kivy-language

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

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

代码版本 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. 是否有另一种(更好的)方式来编码?

非常感谢!

1 个答案:

答案 0 :(得分:0)

这是您的代码的修改版本,它使用 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() 在按下按钮或按键时触发超时重置。