python - 有没有办法让计时器继续跨多个屏幕运行?
问题描述
更改代码后,我得到的错误是 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()
解决方案
问题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=0
from 方法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 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}")
例子
主文件
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'
输出
推荐阅读
- tensorflow - 如何将低级代码从 TF 1 转换为 TF 2
- scala - 为什么我必须传递 new 关键字?
- angular - 有条件地链接多个 observables 的更简洁的方法
- vue.js - 使用 Webpack 4 在 Phoenix 1.4 应用程序中安装 Vue 2
- asp.net-web-api - System.InvalidOperationException(An exception was thrown while attempting to evaluate a LINQ query parameter expression)
- python - 将输出绑定到只读文本输入
- swift - 使用 Swift 获取 RSA 私钥的 n 和 d
- javascript - 呈现相同的视图并防止表单重新提交确认
- android - 不同的活动意图 - 相同的列表
- swift - 函数 prepareForSegue 的强制转换问题