尝试遵循本指南:https://kivy.org/docs/guide/lang.html#accessing-widgets-defined-inside-kv-lang-in-your-python-code
我正在尝试使用id定义访问小部件。这在根小部件中很有效,但它似乎不能在它之外工作。 举个例子,这是一个代表我的问题的最低限度的代码:
GUI.kv文件:
<PlotBox@BoxLayout>:
graph2:graph2_id
BoxLayout:
id:graph2_id
<RootWidget@BoxLayout>:
graph:graph_id
BoxLayout:
id:graph_id
PlotBox:
python文件:
#kivy imports
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
class PlotBox(BoxLayout):
graph2 = ObjectProperty(None)
def __init__(self,**kwargs):
super(PlotBox,self).__init__(**kwargs)
self.graph2.add_widget(Button(text="This doesn't work"))
class RootWidget(BoxLayout):
graph = ObjectProperty(None)
def __init__(self,**kwargs):
super(RootWidget,self).__init__(**kwargs)
self.graph.add_widget(Button(text='This works'))
class GUIApp(App):
def build(self):
self.root = RootWidget()
return self.root
if __name__ == "__main__":
GUIApp().run()
我收到错误:
AttributeError: 'NoneType' object has no attribute 'add_widget'
在RootWidget上,即使我不使用graph = ObjectProperty(None)也能正常工作。 在我的另一个小部件上,它就像id没有被创建一样。
答案 0 :(得分:0)
根据docs:
@字符用于将类名与要子类的类分开。 [...]
从结论来看,它是一种在.kv中类似于python的继承的等效方法,所以你应该只选择其中一种方式。这导致.py的PlotBox永远不会被调用。
另一个错误,根据docs,我不知道它是不是你的错误,但.kv必须是gui.kv,小写。
在执行父构造函数后不会直接加载子元素,因此在构造函数中添加它可能会产生问题,建议和kivy中的常见做法是使用Clock
。
以上所有内容我都用以下代码实现:
<强> gui.kv 强>
<PlotBox>:
graph2:graph2_id
BoxLayout:
id:graph2_id
<RootWidget>:
graph:graph_id
BoxLayout:
id:graph_id
PlotBox:
<强> main.py 强>
#kivy imports
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.clock import Clock
class PlotBox(BoxLayout):
graph2 = ObjectProperty(None)
def __init__(self,**kwargs):
super(PlotBox,self).__init__(**kwargs)
Clock.schedule_once(lambda dt: self.graph2.add_widget(Button(text="This now works")))
class RootWidget(BoxLayout):
graph = ObjectProperty(None)
def __init__(self,**kwargs):
super(RootWidget,self).__init__(**kwargs)
self.graph.add_widget(Button(text='This works'))
class GUIApp(App):
def build(self):
root = RootWidget()
return root
if __name__ == "__main__":
GUIApp().run()
输出:
答案 1 :(得分:0)
我认为在onPlaybackEvent(PlayerEvent playerEvent)
期间尚未设置02-24 13:19:15.500 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playing long song
02-24 13:19:15.516 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyPlay
02-24 13:19:15.574 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:19:15.692 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:19:15.692 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:19:15.692 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyContextChanged
02-24 13:19:15.791 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyTrackChanged
02-24 13:19:15.791 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackEventAudioFlush
- 02-24 13:20:04.286 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playing short song
02-24 13:20:04.307 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyPlay
02-24 13:20:04.357 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:20:04.463 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:20:04.463 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:20:04.463 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyContextChanged
必须在添加任何子项之前返回。
您可以通过执行02-24 13:20:06.020 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playing short song
02-24 13:20:06.035 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyPlay
02-24 13:20:06.088 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:20:06.179 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
02-24 13:20:06.179 5766-5766/<YOUR_PACKAGE> D/MainActivity: Playback event received: kSpPlaybackNotifyMetadataChanged
之类的操作来解决此问题。
答案 2 :(得分:0)
我的工作假设您希望在创建应用程序时运行此代码,不会迟到。
千伏。
<PlotBox>:
BoxLayout:
id:graph2_id
<RootWidget>:
BoxLayout:
id:graph_id
PlotBox:
id: plot
吡啶
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class PlotBox(BoxLayout):
pass
class RootWidget(BoxLayout):
pass
class GUIApp(App):
def build(self):
root = RootWidget()
# We can add things to the Root during build before we return it
# This means we add this information before the user sees anything
root.ids.graph_id.add_widget(Button(text='This works'))
# See end of answer for more about this
root.ids.plot.ids.graph2_id.add_widget(Button(text='This works!'))
return root
if __name__ == "__main__":
GUIApp().run()
首先,您不需要对象属性来访问ID,您可以通过ID或子项来完成:
self.ids.IDGOESHERE
OR
self.children[INDEXOFIDGOESHERE]
关于这一行:
root.ids.plot.ids.graph2_id.add_widget(Button(text='This works!'))
Root有一个带有id'plot'的plotbox类的实例。 Plot类(以及绘图类的所有实例)都有一个BoxLayout实例,其中包含我们可以访问的id图。
所以我们正在做的是:
Root - &gt;情节 - &gt; Graph2
如果我们要添加另一个id为'big_plot'的情节框,那么我们可以做我们之前做的一个Graph2或者我们可以得到一个不同的graph2,因为它属于一个不同的情节框实例。
Root - &gt;情节 - &gt; Graph2
Root - &gt; big_plot - &gt; Graph2
除非你调用super,否则你很少需要在Kivy Widget类中使用init方法(不管怎样我的经验)。
编辑:
如果要重复访问超长地址,可以将它们包装在函数中以获取它们。
示例:
不太好:
def func_one(self):
newtext = 'new'
self.ids.IDONE.ids.IDTWO.ids.IDTHREE.ids.IDFOUR.text = newtext
def func_two(self):
newtext = 'newtwo'
self.ids.IDONE.ids.IDTWO.ids.IDTHREE.ids.IDFOUR.text = newtext
def func_three(self):
newtext = 'newthree'
self.ids.IDSONE.Ids.IDTWO.ids.IDTHREE.ids.IDFOUR.text = newtext
更好:
def long_address(self):
return self.ids.IDSONE.ids.IDSTWO.ids.IDTHREE.ids.IDFOUR
def func_one(self):
newtext = 'new'
self.long_address().text = newtext
def func_two(self):
newtext = 'newtwo'
self.long_address().text = newtext
def func_three(self):
newtext = 'newthree'
self.long_address().text = newtext