Есть ли способ позволить таймеру продолжать работать на нескольких экранах? - PullRequest
0 голосов
/ 03 апреля 2019

После изменения кода я получаю ошибку 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 ]

1 голос
/ 03 апреля 2019

Вопрос 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: у объекта 'super' нет атрибута ' getattr '

первопричина

Трассировка Python показала следующую ошибку перед AttributeError:

Traceback (последний вызов был последним):

Файл "kivy / properties.pyx", строка 840, в kivy.properties.ObservableDict. GetAttr

KeyError: 'navtray'

Во время обработки вышеуказанного исключения произошло другое исключение:

self.current - это имя отображаемого в данный момент экрана или отображаемого экрана.

Когда приложение запускается, отображается первый экран BigScreen, и на этом экране нет id с именем navtray. Из-за отсутствия id: navtray приложение сначала выдало KeyError , а затем AttributeError .

Решение

Существует два решения проблемы.

Метод 1

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__() из class MyScreenManager() и dt=0 из метода 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)

Метод 2

Добавьте 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 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, потому что, нажимая кнопку Forward, мы создали новые экземпляры Screen1 и NavTray1.

Отрывки

файл 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}")

Пример

main.py

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()

main.kv

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

0 голосов
/ 03 апреля 2019

Проблема в том, что вы добавляете новый таймер с каждой новой страницей, которую вы создаете.
Один из способов сохранить тот же таймер - взять первый 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, но для этого нужно внести некоторые изменения в ваш файл kv, и я хотел избежать перезаписи кода ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...