在Kivy中如何通过函数实现向新Screen的过渡?
How in Kivy to implement the transition to a new Screen through the function?
我想在点击按钮后实现到新屏幕的转换,我想通过函数来实现。
我有这个kv代码
<ScreenFrame@BoxLayout>:
orientation: 'vertical'
cols: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
#don't work
on_press: root.manager.current = 'nts'
Button:
text: "Docs"
#don't work
on_release: root.go_to_dcs()
Button:
text: "Videos"
#don't work
on_release: root.manager.current = "vds"
Button:
text: "Pictures"
# don't work
on_release: root.manager.current = 'pctrs'
<NtsScreen>:
BoxLayout:
orientation: "vertical"
cols: 2
ScreenFrame:
Button:
text: "f"
#work, but me need implementaion through function
on_press: root.manager.current = "vds"
<DocsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame:
和这个文件
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.properties import StringProperty
from kivy.uix.widget import Widget
Builder.load_file("main.kv")
class ScreenFrame():
def go_to_dcs(self):
sm.current = "dcs"
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
def go_to_dcs(self):
sm.current = 'dcs'
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))
class MainApp(App):
def build(self):
return sm
if __name__ == "__main__":
MainApp().run()
,但是当我 运行 并按下 Docs 按钮时,出现此错误
Traceback (most recent call last):
File "main.py", line 45, in <module>
MainApp().run()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/app.py", line 826, in run
runTouchApp()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 502, in runTouchApp
EventLoop.window.mainloop()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 403, in mainloop
self._mainloop()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 289, in _mainloop
EventLoop.idle()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 340, in idle
self.dispatch_input()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 325, in dispatch_input
post_dispatch_input(*pop(0))
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 291, in post_dispatch_input
wid.dispatch('on_touch_up', me)
File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/uix/behaviors/button.py", line 179, in on_touch_up
self.dispatch('on_release')
File "kivy/_event.pyx", line 703, in kivy._event.EventDispatcher.dispatch
File "kivy/_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1098, in kivy._event.EventObservers._dispatch
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/lang/builder.py", line 64, in custom_callback
exec(__kvlang__.co_value, idmap)
File "/home/parvektor228/TAOKF/KivyApp/memfier/main.kv", line 32, in <module>
on_release: root.go_to_dcs()
File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'
哪里出错了或者我有什么不懂的地方?
更多细节,以便错误通知消失。
更多细节,以便错误通知消失。
更多详细信息,以便错误通知消失。
出现您的问题是因为 ScreenFrame
是 BoxLayout
(根据您的 kv 文件),而不是 Screen
。因此,您调用的 root
(在本例中为 ScreenFrame
)没有关联的 manager
。 manager
与 Screen
本身相关联。
您必须引用 ScreenFrame
小部件的父级小部件才能引用当前 Screen
,并且它是关联的 manager
。为清楚起见,我建议按如下方式重组您的 Python 代码和 kv 文件:
Python代码:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.widget import Widget
Builder.load_file("testthis.kv")
class ScreenFrame(BoxLayout):
def go_to_screen(self, val):
self.parent.manager.current = val
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
pass
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
class MyScreenManager(ScreenManager):
pass
class MainApp(App):
def build(self):
self.sm = MyScreenManager()
return self.sm
if __name__ == '__main__':
MainApp().run()
kv 文件:
<MyScreenManager>:
NtsScreen:
name: 'nts'
DcsScreen:
name: 'dcs'
VdsScreen:
name: 'vds'
PctrsScreen:
name: 'pctrs'
<NtsScreen>:
ScreenFrame:
<DocsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame:
<ScreenFrame>:
orientation: 'vertical'
rows: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
on_press: root.go_to_screen('nts')
Button:
text: "Docs"
on_release: root.go_to_screen('dcs')
Button:
text: "Videos"
on_release: root.go_to_screen('vds')
Button:
text: "Pictures"
on_release: root.go_to_screen('pctrs')
问题 - 属性错误
有两个AttributeErrors,它们如下:
AttributeError: go_to_dcs() 方法
on_release: root.go_to_dcs()
File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'
在 kv 文件中,定义了 dynamic class、<ScreenFrame@BoxLayout>:
,但没有实现 go_to_dcs()
方法。
属性错误:经理
on_press: root.manager.current = 'nts'
File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
AttributeError: 'ScreenFrame' object has no attribute 'manager'
动态 class、<ScreenFrame@BoxLayout>:
具有 BoxLayout 继承,但没有 Screen 继承。因此,它没有 属性 调用,manager.
解决方案
kv 文件
- 将动态 class、
<ScreenFrame@BoxLayout>:
替换为 class 规则、<ScreenFrame>:
- 在 class 规则中,
<ScreenFrame>:
- 将 root.manager.current
替换为 app.root.current
片段
<ScreenFrame>:
Button:
text: "Notes"
on_press: app.root.current = 'nts'
Button:
text: "Docs"
on_release: root.go_to_dcs()
Button:
text: "Videos"
on_press: app.root.current = 'vds'
Button:
text: "Pictures"
on_press: app.root.current = 'pctrs'
There are three keywords specific to Kv language:
app: always refers to the instance of your application.
root: refers to the base widget/template in the current rule
self: always refer to the current widget
Python代码
- 添加导入语句,
from kivy.uix.boxlayout import BoxLayout
- 将
class ScreenFrame():
替换为class ScreenFrame(BoxLayout):
示例
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_file("main.kv")
class ScreenFrame(BoxLayout):
def go_to_dcs(self):
print("\nScreenFrame.go_to_dcs")
sm.current = "dcs"
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
def go_to_dcs(self):
sm.current = 'dcs'
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))
class MainApp(App):
def build(self):
return sm
if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 1.11.0
<ScreenFrame>:
orientation: 'vertical'
cols: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
on_press: app.root.current = 'nts'
Button:
text: "Docs"
on_release: root.go_to_dcs()
Button:
text: "Videos"
on_press: app.root.current = 'vds'
Button:
text: "Pictures"
on_press: app.root.current = 'pctrs'
<NtsScreen>:
BoxLayout:
orientation: "vertical"
cols: 2
ScreenFrame:
Button:
text: "f"
#work, but me need implementaion through function
on_press: root.manager.current = "vds"
<DcsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame:
输出
我想在点击按钮后实现到新屏幕的转换,我想通过函数来实现。 我有这个kv代码
<ScreenFrame@BoxLayout>:
orientation: 'vertical'
cols: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
#don't work
on_press: root.manager.current = 'nts'
Button:
text: "Docs"
#don't work
on_release: root.go_to_dcs()
Button:
text: "Videos"
#don't work
on_release: root.manager.current = "vds"
Button:
text: "Pictures"
# don't work
on_release: root.manager.current = 'pctrs'
<NtsScreen>:
BoxLayout:
orientation: "vertical"
cols: 2
ScreenFrame:
Button:
text: "f"
#work, but me need implementaion through function
on_press: root.manager.current = "vds"
<DocsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame:
和这个文件
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.properties import StringProperty
from kivy.uix.widget import Widget
Builder.load_file("main.kv")
class ScreenFrame():
def go_to_dcs(self):
sm.current = "dcs"
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
def go_to_dcs(self):
sm.current = 'dcs'
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))
class MainApp(App):
def build(self):
return sm
if __name__ == "__main__":
MainApp().run()
,但是当我 运行 并按下 Docs 按钮时,出现此错误
Traceback (most recent call last):
File "main.py", line 45, in <module>
MainApp().run()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/app.py", line 826, in run
runTouchApp()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 502, in runTouchApp
EventLoop.window.mainloop()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 403, in mainloop
self._mainloop()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 289, in _mainloop
EventLoop.idle()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 340, in idle
self.dispatch_input()
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 325, in dispatch_input
post_dispatch_input(*pop(0))
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 291, in post_dispatch_input
wid.dispatch('on_touch_up', me)
File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/uix/behaviors/button.py", line 179, in on_touch_up
self.dispatch('on_release')
File "kivy/_event.pyx", line 703, in kivy._event.EventDispatcher.dispatch
File "kivy/_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1098, in kivy._event.EventObservers._dispatch
File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/lang/builder.py", line 64, in custom_callback
exec(__kvlang__.co_value, idmap)
File "/home/parvektor228/TAOKF/KivyApp/memfier/main.kv", line 32, in <module>
on_release: root.go_to_dcs()
File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'
哪里出错了或者我有什么不懂的地方?
更多细节,以便错误通知消失。 更多细节,以便错误通知消失。 更多详细信息,以便错误通知消失。
出现您的问题是因为 ScreenFrame
是 BoxLayout
(根据您的 kv 文件),而不是 Screen
。因此,您调用的 root
(在本例中为 ScreenFrame
)没有关联的 manager
。 manager
与 Screen
本身相关联。
您必须引用 ScreenFrame
小部件的父级小部件才能引用当前 Screen
,并且它是关联的 manager
。为清楚起见,我建议按如下方式重组您的 Python 代码和 kv 文件:
Python代码:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.widget import Widget
Builder.load_file("testthis.kv")
class ScreenFrame(BoxLayout):
def go_to_screen(self, val):
self.parent.manager.current = val
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
pass
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
class MyScreenManager(ScreenManager):
pass
class MainApp(App):
def build(self):
self.sm = MyScreenManager()
return self.sm
if __name__ == '__main__':
MainApp().run()
kv 文件:
<MyScreenManager>:
NtsScreen:
name: 'nts'
DcsScreen:
name: 'dcs'
VdsScreen:
name: 'vds'
PctrsScreen:
name: 'pctrs'
<NtsScreen>:
ScreenFrame:
<DocsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame:
<ScreenFrame>:
orientation: 'vertical'
rows: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
on_press: root.go_to_screen('nts')
Button:
text: "Docs"
on_release: root.go_to_screen('dcs')
Button:
text: "Videos"
on_release: root.go_to_screen('vds')
Button:
text: "Pictures"
on_release: root.go_to_screen('pctrs')
问题 - 属性错误
有两个AttributeErrors,它们如下:
AttributeError: go_to_dcs() 方法
on_release: root.go_to_dcs() File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__ AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'
在 kv 文件中,定义了 dynamic class、<ScreenFrame@BoxLayout>:
,但没有实现 go_to_dcs()
方法。
属性错误:经理
on_press: root.manager.current = 'nts' File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__ AttributeError: 'ScreenFrame' object has no attribute 'manager'
动态 class、<ScreenFrame@BoxLayout>:
具有 BoxLayout 继承,但没有 Screen 继承。因此,它没有 属性 调用,manager.
解决方案
kv 文件
- 将动态 class、
<ScreenFrame@BoxLayout>:
替换为 class 规则、<ScreenFrame>:
- 在 class 规则中,
<ScreenFrame>:
- 将root.manager.current
替换为app.root.current
片段
<ScreenFrame>:
Button:
text: "Notes"
on_press: app.root.current = 'nts'
Button:
text: "Docs"
on_release: root.go_to_dcs()
Button:
text: "Videos"
on_press: app.root.current = 'vds'
Button:
text: "Pictures"
on_press: app.root.current = 'pctrs'
There are three keywords specific to Kv language:
app: always refers to the instance of your application.
root: refers to the base widget/template in the current rule
self: always refer to the current widget
Python代码
- 添加导入语句,
from kivy.uix.boxlayout import BoxLayout
- 将
class ScreenFrame():
替换为class ScreenFrame(BoxLayout):
示例
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_file("main.kv")
class ScreenFrame(BoxLayout):
def go_to_dcs(self):
print("\nScreenFrame.go_to_dcs")
sm.current = "dcs"
class NtsScreen(Screen):
pass
class DcsScreen(Screen):
def go_to_dcs(self):
sm.current = 'dcs'
class VdsScreen(Screen):
pass
class PctrsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))
class MainApp(App):
def build(self):
return sm
if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 1.11.0
<ScreenFrame>:
orientation: 'vertical'
cols: 3
ActionBar:
ActionView:
pos_hint: {'top':1}
use_separator: True
ActionPrevious:
title: "Title"
with_previous: False
ActionButton:
text: "+"
Label:
text: "Content"
BoxLayout:
orientation: 'horizontal'
cols: 4
size_hint: 1, 0.15
Button:
text: "Notes"
on_press: app.root.current = 'nts'
Button:
text: "Docs"
on_release: root.go_to_dcs()
Button:
text: "Videos"
on_press: app.root.current = 'vds'
Button:
text: "Pictures"
on_press: app.root.current = 'pctrs'
<NtsScreen>:
BoxLayout:
orientation: "vertical"
cols: 2
ScreenFrame:
Button:
text: "f"
#work, but me need implementaion through function
on_press: root.manager.current = "vds"
<DcsScreen>:
ScreenFrame:
<VdsScreen>:
ScreenFrame:
<PctrsScreen>:
ScreenFrame: