目标
我想创建一个可以动态添加按钮的小脚本,但仍然可以让我通过root对特定按钮执行功能。
我的方法
我做了这个脚本。
它能够在顶部动态添加大按钮。
当按下这些按钮时,每个按钮都会略微改变其自身的颜色。
它的底部有两个小按钮。
第一个按钮会在顶部动态添加新的大按钮。
第二个按钮重置顶部第一个大按钮的颜色。
我的代码
#!/usr/bin/env python3
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<RootWidget>:
Button:
text: 'Add'
size_hint: (None, None)
size: (40, 40)
pos: (40, 40)
group: 'action'
on_press: root.createNextTarget()
Button:
text: 'res'
size_hint: (None, None)
size: (40, 40)
pos: (100, 40)
group: 'action'
on_press: root.resetTarget()
''')
class RootWidget(FloatLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
#note: self.ids isn't populated yet. I guess we can't use it yet.
self.createNextTarget()
def resetTarget(self):
f_target = self.ids['targetbutton0']
f_target.background_color = (1.0, 1.0, 1.0, 1.0)
return True
def countTargets(self):
return [str(x.__class__.__name__) for x in self.children if x != None].count('TargetButton')
def createNextTarget(self):
f_nextButton = TargetButton(id="targetbutton"+str(self.countTargets()),
size_hint=(None, None),
pos=(80 + (10 + 60) * self.countTargets(), 100),
size=(60, 60),
background_normal = '',
background_color = (1, 1, 1, 1),
group = 'target')
self.add_widget(f_nextButton)
f_nextButton.bind(on_press=TargetButton.lowerAllRGB)
class TargetButton(Button):
def __init__(self, **kwargs):
super(TargetButton, self).__init__(**kwargs)
def lowerAllRGB(self):
f_r, f_g, f_b, f_a = self.background_color
if f_r >= 0.1: f_r = f_r - 0.1
if f_g >= 0.1: f_g = f_g - 0.1
if f_b >= 0.1: f_b = f_b - 0.1
self.background_color = (f_r, f_g, f_b, f_a)
return True
class TestApp(App):
def build(self):
return RootWidget()
def on_stop(self):
print("TestApp.on_stop: finishing", self.root.ids)
if __name__ == '__main__':
TestApp().run()
问题
如果我尝试按下重置按钮(通过root.ids
访问小部件),则会收到错误消息:KeyError: 'targetbutton0'
找到a post about a similar problem后,我以为root.ids
在RootWidget.__init__
期间不起作用。
但是,当我在RootWidget.__init__
完成之后使用按钮添加按钮时,TestApp.on_stop()
仍会打印:
TestApp.on_stop:完成{}
所以root.ids
仍然是空的,尽管我为每个小部件都分配了id属性,但似乎不包含任何动态添加的小部件。
我对您的问题
root.ids
就我的目的而言就一文不值了吗?答案 0 :(得分:1)
鉴于我动态添加小部件的方式,只是使用root.ids 对我而言毫无价值?
id
不存储在self.ids
或root.ids
中。因此,您无法使用self.ids['targetbutton0']
或self.ids.targetbutton0
访问动态添加的窗口小部件。如果这样做,您将得到一个KeyError
,因为在字典类型属性self.ids
中找不到它。
解析您的kv
文件时,Kivy会收集所有标记有ID的小部件,并将它们放在此 self.ids
字典类型属性中。
注意:
这些类型的id
(即分配给动态创建的小部件的id
)已弃用,并将在以后的Kivy版本中删除。
[WARNING] Deprecated property "<StringProperty name=id>" of object "<kivy.uix.button.Button object at 0x7feeec0968d0>" has been set, it will be removed in a future version
我是否可以通过id访问我的小部件?
您可以创建自己的字典类型属性ID列表。
from kivy.properties import DictProperty
class RootWidget(FloatLayout):
dynamic_ids = DictProperty({}) # declare class attribute, dynamic_ids
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.createNextTarget()
def resetTarget(self):
f_target = self.dynamic_ids['targetbutton0']
f_target.background_color = (0.0, 1.0, 1.0, 1.0) # cyan colour
return True
...
def createNextTarget(self):
id = "targetbutton" + str(self.countTargets())
f_nextButton = TargetButton(id=id,
size_hint=(None, None),
pos=(80 + (10 + 60) * self.countTargets(), 100),
size=(60, 60),
background_normal = '',
background_color = (1, 1, 1, 1), # white colour
group = 'target')
self.add_widget(f_nextButton)
self.dynamic_ids[id] = f_nextButton
f_nextButton.bind(on_press=TargetButton.lowerAllRGB)