【问题标题】:address dynamically created label地址动态创建的标签
【发布时间】:2019-12-30 23:15:21
【问题描述】:

我尝试创建一个简单的计数应用程序。 我有按钮和标签,它们是通过 for 循环创建的。 on_press 按钮,对应的标签应该更新为一个新值(当前数字加一)。

这里是.py文件的对应部分:

class ScreenCounter(Screen): 
    numberButtons = 0
    def on_enter(self):
        for i in range(len(birdname)):
            self.image = Image(source=birdimage[i])
            buttonName = 'bird'+str(i)
            self.button = Button(id=buttonName,text=birdname[i],on_press=self.onClick)
            labelName='birdCount'+str(i)
            self.label = Label(id=labelName, text='0')
            self.ids.grid.add_widget(self.image)
            self.ids.grid.add_widget(self.button)
            self.ids.grid.add_widget(self.label)
            self.numberButtons += 1

    def addCounter(self):
        layout = GridLayout(cols = 1, padding = 10) 

        self.popupLabel = TextInput(text = "", size_hint = [1, .7])
        saveButton = Button(text = "Speichern", size_hint = [1, .2])
        closeButton = Button(text = "Ende", size_hint = [1, .2]) 

        layout.add_widget(self.popupLabel) 
        layout.add_widget(saveButton)      
        layout.add_widget(closeButton)       

        popup = Popup(title ='Vogelname eingeben', 
                    content = layout,
                    size_hint = (0.7, 0.4),
                    pos_hint = {'center_x': 0.5,'center_y': 0.5})   
        popup.open()
        saveButton.bind(on_press = self.save, on_release = popup.dismiss)     
        closeButton.bind(on_press = popup.dismiss)

    def save(self, *args):
        buttonName = 'bird'+str(self.numberButtons)
        self.button = Button(id=buttonName,text=str(self.popupLabel.text),on_press=self.onClick)
        labelName='birdCount'+str(self.numberButtons)
        self.label = Label(id=labelName, text='0')
        self.ids.grid.add_widget(Label(text=''))
        self.ids.grid.add_widget(self.button)
        self.ids.grid.add_widget(self.label)
        self.numberButtons += 1

    def onClick(self, instance):
        print(int(instance.id[4:]))
        labelNumber = int(instance.id[4:])
        labelName = 'birdCount'+str(labelNumber)
        print(labelName)
        self.ids.grid.ids.labelName.text = 'new'

.kv 部分如下所示:

<ScreenCounter>: 
    canvas.before:
        Color:
            rgba: 1, 1, 1, 0.3
        Rectangle:
            pos: self.pos
            size: self.size

    BoxLayout:
        orientation : 'vertical'
        Button: 
            id: newCounter
            text: "Neuer Zähler" 
            background_color : 1, 0, 0, 1 
            font_size: 80
            size_hint: 1, .1
            on_press:
                root.addCounter()

        GridLayout:
            orientation: 'horizontal'
            id: grid
            cols: 3
            spacing: 5
            padding: 5

主要问题是,我无法更改相应标签的文本,因为我无法解决它。如果我尝试解决例如id 为“newCounter”的按钮,但由于标签是在 GridLayout 内的“网格”内创建的,因此它似乎失败了。我收到以下错误:

 Traceback (most recent call last):
   File "kivy/properties.pyx", line 860, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'labelName'
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/Users/jeff/python/birdcount/main.py", line 113, in <module>
     MyApp().run()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/app.py", line 855, in run
     runTouchApp()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 504, in runTouchApp
     EventLoop.window.mainloop()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/window_sdl2.py", line 747, in mainloop
     self._mainloop()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/window_sdl2.py", line 479, in _mainloop
     EventLoop.idle()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 342, in idle
     self.dispatch_input()
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 327, in dispatch_input
     post_dispatch_input(*pop(0))
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/base.py", line 233, in post_dispatch_input
     listener.dispatch('on_motion', etype, me)
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/__init__.py", line 1402, in on_motion
     self.dispatch('on_touch_down', me)
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/__init__.py", line 1418, in on_touch_down
     if w.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/screenmanager.py", line 1191, in on_touch_down
     return super(ScreenManager, self).on_touch_down(touch)
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/widget.py", line 549, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/relativelayout.py", line 288, in on_touch_down
     ret = super(RelativeLayout, self).on_touch_down(touch)
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/widget.py", line 549, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/widget.py", line 549, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/widget.py", line 549, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/uix/behaviors/button.py", line 151, in on_touch_down
     self.dispatch('on_press')
   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 1138, in kivy._event.EventObservers._dispatch
   File "/Users/jeff/python/birdcount/main.py", line 84, in onClick
     self.ids.grid.ids.labelName.text = 'new'
   File "kivy/properties.pyx", line 863, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

这是我的第一篇文章,所以我不确定我是否提供了所有需要的信息。 此外,我是 kivy/python 的新手,这是我的第一个“边做边学”应用程序,所以如果您有改进建议,我很乐意阅读。

现在谢谢!

编辑:

这是一个最小的工作示例:

# bird_count - main.py
import kivy
import os
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout

counterKV = Builder.load_file("counter.kv")
birdname = ['Amsel', 'Drossel','Buchfink']

class ScreenMain(Screen): 
    pass

class ScreenCounter(Screen): 
    numberButtons = 0
    def on_enter(self):
        for i in range(len(birdname)):
            buttonName = 'bird'+str(i)
            self.button = Button(id=buttonName,text=birdname[i],on_press=self.onClick)
            labelName='birdCount'+str(i)
            self.label = Label(id=labelName, text='0')
            self.ids.grid.add_widget(self.button)
            self.ids.grid.add_widget(self.label)
            self.numberButtons += 1
    
    def onClick(self, instance):
        pass
        # here, the corresponding label should add 1 whenever the button is pressed
        #self.ids.grid.ids.labelID.text = int(labelID.text)+1

class Manager(ScreenManager):
    pass

class MyApp(App):
    def build(self):
       return Manager()

if __name__ == '__main__':
    MyApp().run()

.kv:

: 导入 sm kivy.uix.screenmanager

<Manager>:
    ScreenMain:
        name: 'ScreenMain'
    ScreenCounter:
        name: 'ScreenCounter'


<ScreenMain>: 

    BoxLayout: 
        Button: 
            text: "Neue Zählung" 
            background_color : 0.12, 0.42, 0.23, 1  
            on_press: 
                root.manager.transition.direction = 'left' 
                root.manager.transition.duration = 0.3
                root.manager.current = 'ScreenCounter'
      
<ScreenCounter>: 

    BoxLayout:
        GridLayout:
            orientation: 'horizontal'
            id: grid
            cols: 3
            spacing: 5
            padding: 5

我无法删除第一个屏幕,或者我遇到了另一个错误:-|

【问题讨论】:

  • 你能提供一个最小的可运行示例吗?

标签: python kivy


【解决方案1】:

ids 字典是在加载 kv 文件/字符串时创建的。您在kv 之外创建的任何id 都只是Widget 的一个属性,不会出现在ids 中。因此,您需要为自己创建一种方法来维护对标签的引用。一个简单的方法是只保留它们的列表。这是您的ScreenCounter 课程的修改版本(来自您的mcve),我认为它可以满足您的需求:

class ScreenCounter(Screen):
    numberButtons = 0

    def __init__(self, **kwargs):
        super(ScreenCounter, self).__init__(**kwargs)
        self.labels = []    # create a list of labels

    def on_enter(self):
        for i in range(len(birdname)):
            buttonName = 'bird'+str(i)
            self.button = Button(id=buttonName,text=birdname[i],on_press=self.onClick)
            labelName='birdCount'+str(i)
            self.label = Label(id=labelName, text='0')
            self.labels.append(self.label)     # add this label to the list of labels
            self.ids.grid.add_widget(self.button)
            self.ids.grid.add_widget(self.label)
            self.numberButtons += 1

    def onClick(self, instance):
        labelNumber = int(instance.id[4:])

        # Access the label via the list
        self.labels[labelNumber].text = str(int(self.labels[labelNumber].text) + 1)

另一种可能性是创建自己的id 字典。这是另一个版本的ScreenCounter,使用名为myIds 的字典:

class ScreenCounter(Screen):
    numberButtons = 0

    def __init__(self, **kwargs):
        super(ScreenCounter, self).__init__(**kwargs)
        self.myIds = {}    # create a dictionary of labels

    def on_enter(self):
        for i in range(len(birdname)):
            buttonName = 'bird'+str(i)
            self.button = Button(id=buttonName,text=birdname[i],on_press=self.onClick)
            labelName='birdCount'+str(i)
            self.label = Label(id=labelName, text='0')
            self.myIds[labelName] = self.label    # add this label to the myIds dictionary
            self.ids.grid.add_widget(self.button)
            self.ids.grid.add_widget(self.label)
            self.numberButtons += 1

    def onClick(self, instance):
        labelNumber = int(instance.id[4:])
        labelName = 'birdCount'+str(labelNumber)

        # Access the label via myIds
        self.myIds[labelName].text = str(int(self.myIds[labelName].text) + 1)

【讨论】:

    猜你喜欢
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 2022-12-22
    • 2012-05-21
    • 2012-04-17
    • 1970-01-01
    相关资源
    最近更新 更多