【问题标题】:Kivy screenmanager: switching screen after timeout with signalKivy screenmanager:超时后切换屏幕与信号
【发布时间】:2021-01-22 01:16:49
【问题描述】:

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

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

代码版本 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 都是该函数中的未定义变量。 在第二个版本中,我不明白为什么设置屏幕是空白的。

编辑 ***第三版代码***

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. 还有其他(更好的)编码方式吗?

非常感谢!

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

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

    【讨论】:

    • 太好了,谢谢!时钟和 on_touch/key 事件非常有用—— sm.current 用于切换屏幕,但我不明白为什么 sm.switch_to 起作用
    • documentation for switch_to 太糟糕了。它没有提到旧的Screen 已从ScreenManager 中删除。您可以将所有Screens 添加到ScreenManager 并使用sm.current 进行切换,或者不添加任何ScreensScreenManager 并使用sm.switch_to()。只有小心翼翼地混合使用这两种方法才能取得成功。
    猜你喜欢
    • 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
    相关资源
    最近更新 更多