有没有办法允许计时器继续在多个屏幕上运行?

时间:2019-04-03 11:08:49

标签: python kivy

更改代码后,我得到的错误是AttributeError:'super'对象的行没有属性' getattr '

self.get_screen(self.current).ids.navtray.ids.label_timer.text =“ {0:.2f} secs” .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()

2 个答案:

答案 0 :(得分:1)

问题2

  

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

     

文件“ kivy / properties.pyx”,第843行,位于   kivy.properties.ObservableDict。 getattr

     

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

根本原因

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

  

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

     

文件“ kivy / properties.pyx”,行840,在   kivy.properties.ObservableDict。 getattr

     

KeyError:'navtray'

     

在处理上述异常期间,发生了另一个异常:

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

运行该应用程序时,显示的第一个屏幕为BigScreen,在此屏幕中没有名为id的{​​{1}}。由于缺少id:navtray,该应用程序先引发 KeyError ,然后引发 AttributeError

解决方案

有两种解决方法。

方法1

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

片段
new_page()

2)在Python脚本中,从 Button: text: 'Lets Begin' font_size: 24 on_press: app.root.new_page() on_press: app.root.start() 中删除构造函数__init__(),从方法class MyScreenManager()中删除dt=0

片段
start()

方法2

添加 if语句以检查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)

摘要

self.current

问题1

  

想要计时器在多个屏幕上连续运行

解决方案

  • 将类属性和在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) 中定义的所有方法移动到class NavTray1
  • 使用class MyScreenManager从方法Label更新NavTray1实例中increment_time的文本。我们之所以使用self.get_screen(self.current).ids.navtray.ids.label_timer.text = "{0:.2f} secs".format(self.number)是因为当我们按下self.current按钮时,我们已经创建了ForwardScreen1的新实例。

摘要

kv文件

NavTray1

py文件

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

Button:
    id: submit_button

示例

main.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}")

main.kv

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 ScreenManager - Timer runs continuously across multiple screens

答案 1 :(得分:0)

问题是您在创建的每个新页面上添加了一个 new 计时器。
保持相同计时器的一种方法是采用第一个startsWith,并在下一页中使用它。
为此,您必须像这样更改NavTray1方法:

new_page

可以通过保留对def new_page(self): box = self.current_screen.ids["box"] navtray = box.children[0] # get the original Navtray1 here box.remove_widget(navtray) name = str(time.time()) s = Screen1(name=name) new_box = s.ids["box"] new_box.remove_widget(new_box.children[0]) # remove the current NavTray1 new_box.add_widget(navtray) # add the original Navtray1 here self.add_widget(s) self.current = name 的引用来更好地完成此操作,但这需要对NavTray1文件进行一些更改,我想避免重写代码。