首页 > 解决方案 > 有没有办法让计时器继续跨多个屏幕运行?

问题描述

更改代码后,我得到的错误是 AttributeError: 'super' object has no attribute ' getattr ' 的行:

self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} 秒".format(self.number)

我想知道这个错误背后的含义,以便下次我也可以解决这个问题。谢谢。

from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition, WipeTransition
from kivy.clock import Clock
from kivy.properties import (StringProperty, NumericProperty, ObjectProperty,
                             ListProperty, DictProperty, BooleanProperty)
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
import time
import random
from kivy.uix.label import Label

class SubjectsLayout(GridLayout):
    pass

class NavTray1(BoxLayout):
    pass

class Screen1(Screen):
    pass

class BeginScreen(Screen):
    pass


class MyScreenManager(ScreenManager):
    number = NumericProperty(0)

    def __init__(self, **kwargs):
        super(MyScreenManager, self).__init__(**kwargs)
        Clock.schedule_once(lambda dt: self.start(), 0.5)

    def increment_time(self, interval):
        self.number += .01
        self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)

    def start(self, dt=0):
        self.timer = Clock.schedule_interval(self.increment_time, .01)

    def stop(self):
        Clock.unschedule(self.timer)
        print(f"timer={self.number}")

    def new_page(self):
        name = str(time.time())
        s = Screen1(name=name)
        self.add_widget(s)
        self.current = name

Login = Builder.load_string('''
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
#: import ScrollEffect kivy.effects.scroll.ScrollEffect
#: import SlideTransition kivy.uix.screenmanager.SlideTransition


MyScreenManager:
    transition: FadeTransition()
    BeginScreen:
    Screen1:

<NavTray1>:
    orientation: 'horizontal'
    padding: '5dp'
    spacing: '5dp'
    canvas.before:
        Color: 
            rgb: .1, .1, .1
        Rectangle:
            size: self.size
            pos: self.pos
    Button:
        color: [0.4, 0.4, 0.4, 1]
        size_hint: (.33, None)
        height: '80dp'
        text: 'Back'
        on_release : app.root.transition = SlideTransition(direction='right')
        on_release : app.root.current = app.root.previous()

    BoxLayout:
        orientation: 'vertical'
        size_hint: (.33, 1.0)
        id: custom
        Label:
            id: label_timer

    Button:
        id: submit_button
        color: [6/255, 114/255, 0, 1]
        size_hint: (.33, None)
        height: '80dp'
        text: 'Forward'
        background_color: [28/138, 1, 35/138, 0.5]
        on_release : app.root.new_page()
        on_release : app.root.transition = SlideTransition(direction='left')

<Screen1>:
    name: "start"
    BoxLayout:
        orientation: 'vertical'
        size: root.size
        pos: root.pos
        id: box
        ScrollView:
            size_hint: (1.0, None)
            height: root.height - navtray.height
            SubjectsLayout:
                id: subjects
                cols: 1
                Label:
                    text: root.name
        NavTray1:
            size_hint: (1.0, None)
            id: navtray
            height: '90dp'

<BeginScreen>:
    name: "begin"
    FloatLayout:
        Label:
            text: 'begin'
            font_size: 50
            pos_hint: {'x':.35, 'y':.45}
            color: [0,1,0,1]

        Button:
            text: 'Lets Begin'
            font_size: 24
            on_press: app.root.new_page()
            size_hint: (.4,.25)
            pos_hint: {"center_x":.5, "center_y":.5}
            color: [0,0,0,1]

''')

class MyApp(App):
    def build(self):
        return Login

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

标签: pythonkivy

解决方案


问题2

self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} 秒".format(self.number)

文件“kivy/properties.pyx”,第 843 行,位于 kivy.properties.ObservableDict。获取属性

AttributeError:“超级”对象没有属性“ getattr

根本原因

Python 的 Traceback 在 AttributeError 之前显示以下错误:

回溯(最近一次通话最后):

文件“kivy/properties.pyx”,第 840 行,位于 kivy.properties.ObservableDict。获取属性

键错误:'navtray'

在处理上述异常的过程中,又出现了一个异常:

self.current是当前显示的屏幕的名称,或要显示的屏幕。

当应用程序运行时,显示的第一个屏幕是BigScreen并且在此屏幕中没有id调用navtray. 由于缺少 id: navtray,应用程序先抛出 KeyError ,然后再抛出AttributeError

解决方案

该问题有两种解决方案。

方法一

1)在kv文件中,在调用方法start()之后添加对方法的调用new_page()

片段
    Button:
        text: 'Lets Begin'
        font_size: 24
        on_press: app.root.new_page()
        on_press: app.root.start()

2) 在 Python 脚本中,删除构造函数,__init__()fromclass MyScreenManager()dt=0from 方法start()

片段
class MyScreenManager(ScreenManager):
    number = NumericProperty(0)

    def increment_time(self, dt):
        self.number += .01
        self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)

    def start(self):
        self.timer = Clock.schedule_interval(self.increment_time, .01)

方法二

添加if 语句进行检查self.current

片段

def increment_time(self, interval):
    self.number += .01
    if self.current == 'begin':
        self.get_screen('start').ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)
    else:
        self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)

问题 1

希望计时器在多个屏幕上连续运行

解决方案

  • 将类属性和定义的所有方法移动class NavTray1class MyScreenManager
  • 使用方法更新实例中Label的文本。我们正在使用,因为当我们按下按钮时,我们创建了和的新实例。NavTray1increment_timeself.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)self.currentForwardScreen1NavTray1

片段

.kv 文件

BoxLayout:
    orientation: 'vertical'
    size_hint: (.33, 1.0)
    id: custom
    Label:
        id: label_timer

Button:
    id: submit_button

.py 文件

class NavTray1(BoxLayout):
    pass

...
class MyScreenManager(ScreenManager):
    number = NumericProperty(0)

    def __init__(self, **kwargs):
        super(MyScreenManager, self).__init__(**kwargs)
        Clock.schedule_once(lambda dt: self.start(), 0.5)

    def increment_time(self, interval):
        self.number += .01
        self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)

    def start(self):
        self.timer = Clock.schedule_interval(self.increment_time, .01)

    def stop(self):
        Clock.unschedule(self.timer)
        print(f"timer={self.number}")

例子

主文件

from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
import time


class SubjectsLayout(GridLayout):
    pass


class NavTray1(BoxLayout):
    pass


class Screen1(Screen):
    pass


class MyScreenManager(ScreenManager):
    number = NumericProperty(0)

    def __init__(self, **kwargs):
        super(MyScreenManager, self).__init__(**kwargs)
        Clock.schedule_once(lambda dt: self.start(), 0.5)

    def increment_time(self, interval):
        self.number += .01
        self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)

    def start(self):
        self.timer = Clock.schedule_interval(self.increment_time, .01)

    def stop(self):
        Clock.unschedule(self.timer)
        print(f"timer={self.number}")


    def new_page(self):
        name = str(time.time())
        s = Screen1(name=name)
        self.add_widget(s)
        self.current = name


Login = Builder.load_file("main.kv")


class MyApp(App):
    def build(self):
        return Login


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

主文件

#:kivy 1.11.0
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import ScrollEffect kivy.effects.scroll.ScrollEffect
#:import SlideTransition kivy.uix.screenmanager.SlideTransition


MyScreenManager:
    transition: FadeTransition()
    Screen1:

<NavTray1>:
    orientation: 'horizontal'
    padding: '5dp'
    spacing: '5dp'
    canvas.before:
        Color:
            rgb: .1, .1, .1
        Rectangle:
            size: self.size
            pos: self.pos
    Button:
        color: [0.4, 0.4, 0.4, 1]
        size_hint: (.33, None)
        height: '80dp'
        text: 'Back'
        on_release : app.root.transition = SlideTransition(direction='right')
        on_release : app.root.current = app.root.previous()


    BoxLayout:
        orientation: 'vertical'
        size_hint: (.33, 1.0)
        id: custom
        Label:
            id: label_timer

    Button:
        id: submit_button
        color: [6/255, 114/255, 0, 1]
        size_hint: (.33, None)
        height: '80dp'
        text: 'Forward'
        background_color: [28/138, 1, 35/138, 0.5]
        on_release : app.root.new_page()
        on_release : app.root.transition = SlideTransition(direction='left')

<Screen1>:
    name: "start"
    BoxLayout:
        orientation: 'vertical'
        size: root.size
        pos: root.pos
        id: box
        ScrollView:
            size_hint: (1.0, None)
            height: root.height - navtray.height
            SubjectsLayout:
                id: subjects
                cols: 1
                Label:
                    text: root.name
        NavTray1:
            size_hint: (1.0, None)
            id: navtray
            height: '90dp'

输出

Kivy ScreenManager - 计时器在多个屏幕上连续运行


推荐阅读