【发布时间】:2014-10-06 20:31:45
【问题描述】:
我在理解 Python 和 Kivy 语言之间的通信时遇到问题 - 具体如下。
情况
我有一个应用程序 - TutorialApp 和 build 方法返回 MyScreenManager()。 MyScreenManager 只管理一个名为 FirstScreen 的屏幕。在相应的tutorial.kv 文件中,我给FirstScreen BoxLayout 小部件和id: box。假设我有一个列表
FILMS = ['Film 1', 'Film 2']
现在,当我运行应用程序时,我想为每部电影添加一个 Button 小部件到 ID 为 box 的 BoxLayout。这应该只做一次,所以我想把它放在__init__ 函数中,我用super 方法覆盖它。这是我的main.py 文件:
#!/usr/bin/env python
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
FILMS = ['Film 1', 'Film 2']
class TutorialApp(App):
def build(self):
return MyScreenManager()
class MyScreenManager(ScreenManager):
pass
class FirstScreen(Screen):
def __init__(self, **kvargs):
super(FirstScreen, self).__init__(**kvargs)
for film in FILMS:
self.ids.box.add_widget(Button(text=film))
if __name__ == '__main__':
TutorialApp().run()
这是我的tutorial.kv 文件:
<MyScreenManager>:
FirstScreen:
<FirstScreen>:
name: 'FirstScreen'
BoxLayout:
id: box
但我的方法不起作用。为什么?可能是因为当时调用__init__的时候没有BoxLayout也没有id,所以无法引用(至少我根据日志是这样认为的,也通过打印测试了self.ids 不同时间)。
不同的方法
现在,我能做的是以下事情。我可以像这样简单地调整代码(仅显示更改的部分),而不是在 tutorial.kv 文件中创建 BoxLayout:
class FirstScreen(Screen):
def __init__(self, **kvargs):
super(FirstScreen, self).__init__(**kvargs)
box = BoxLayout(id='box')
for film in FILMS:
box.add_widget(Button(text=film))
self.add_widget(box)
还有tutorial.kv:
<MyScreenManager>:
FirstScreen:
<FirstScreen>:
name: 'FirstScreen'
这可行,但后来我遇到了其他问题。假设我有更多屏幕,我想在我的FirstScreeen 中添加一个Button,这将导致不同的屏幕(示例中未指定)。因此,Button 将在 tutorial.kv 中指定,如下所示:
Button:
text: 'Go somewhere else'
on_release: app.root.current = 'DifferentScreenName'
但由于我在 __init__ 函数中创建了该框,我不能简单地将这段代码放入 tutorial.kv 中。我可以像这样更改main.py:
class FirstScreen(Screen):
def __init__(self, **kvargs):
super(FirstScreen, self).__init__(**kvargs)
box = BoxLayout(id='box')
for film in FILMS:
box.add_widget(Button(text=film))
box.add_widget(Button(text='Go somewhere else',
on_release="""WHAT SHOULD GO HERE?"""))
self.add_widget(box)
但是正如应该在这里做什么?我不知道如何改变屏幕。所以,希望你能理解这个问题。我不知道哪种方式更好,我认为*.kv文件中指定应用程序布局的内容越多越好,但是如何解决类似这种情况?
我的猜测
我知道这很长,但我想向您保证,我自己也尝试过。
初步猜测
例如,在 tutorial.kv 内调用类似 on_init/on_start 的内容:
<MyScreenManager>:
FirstScreen:
DifferentScreen:
<FirstScreen>:
name: 'FirstScreen'
BoxLayout:
id:box
on_start: root.method_which_adds_film_buttons
Button:
text: 'Go somewhere else'
on_release: app.root.current ='DifferentScreen'
希望这种方法在FirstScreen 初始化时只运行一次。但是我找不到这样的方法。
第二次猜测
像这样调整__init__函数:
类FirstScreen(屏幕):
def __init__(self, **kvargs):
super(FirstScreen, self).__init__(**kvargs)
box = BoxLayout(id='box')
for film in FILMS:
box.add_widget(Button(text=film))
box.add_widget(Button(text='Go somewhere else',
on_release=app.root.current('DifferentScreen')))
self.add_widget(box)
或者这个:
class FirstScreen(Screen):
def __init__(self, **kvargs):
super(FirstScreen, self).__init__(**kvargs)
box = BoxLayout(id='box')
for film in FILMS:
box.add_widget(Button(text=film))
box.add_widget(Button(text='Go somewhere else',
on_release=self.root.current('DifferentScreen')))
self.add_widget(box)
显然两者都不起作用(这就是我在这里问的原因)。这两个例子都表明,我不明白root 是如何传递的。有人可以解释/给出我正在寻找的行为的工作示例吗?
【问题讨论】:
-
感谢 Kivy IRC 用户
我得到了以下答案,这可以解决问题:gist.github.com/anonymous/cdac178934b73eae51e0 -
请将链接粘贴到答案中并标记为已解决,这样它就不会出现在未解决的问题中。 TNX