在 kivy 中通过回调传递对象——链接对象的好主意?

passing objects through callbacks in kivy- a good idea for linking objects?

对于 voteapp 假设在它的 kv 文件中我定义了一个切换按钮:

....
...
ToggleButton:
    id: toggle_visibility
    size_hint_x: 0.27
    text: "Hide"
    on_press: root.toggle_visibility(self) #<-----------

注意上面标记的行,将小部件作为参数传递给回调函数而不是注册 ObjectProperty() 并链接到它的 ID 有什么问题吗?当我稍后执行时,我收到一个 NoneType 对象返回的事件错误,例如出于某种原因按下按钮,所以我选择了前者。

编辑:我已经将导致 Nonetype 对象返回消息的错误代码放在末尾的回溯中。

执行以下代码时出现错误:

在 main.py 文件中:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty


class Apibar(BoxLayout):
    api_input_bar = ObjectProperty()
    toggle_visibility_button = ObjectProperty()  

    #some code here  not shown to keep minimal; only regular methods  

    def toggle_visibility(self):
        #wanting to change the text inside the text input key
        self.api_input_bar.text="your api key"

.kv 文件中的代码是:

<Apibar>:
    BoxLayout:
        orientation:"vertical"
        padding: "5dp"
        api_input_bar: api_input
        toggle_visibility_button : toggle_visibility
        BoxLayout:
              orientation: "horizontal"
              size_hint_y: 0.5
              #some more rules for other widgets
              ToggleButton:
                  id: toggle_visibility
                  size_hint_x: 0.27
                  text: "Hide"
                  on_press: root.toggle_visibility()
                  #some more rules for other widgets

终端的回溯是:

File "main.py", line 43, in <module>
     pictureapp().run()
   File "/usr/lib/python3/dist-packages/kivy/app.py", line 828, in run
     runTouchApp()
   File "/usr/lib/python3/dist-packages/kivy/base.py", line 504, in runTouchApp
     EventLoop.window.mainloop()
   File "/usr/lib/python3/dist-packages/kivy/core/window/window_sdl2.py", line 663, in mainloop
     self._mainloop()
   File "/usr/lib/python3/dist-packages/kivy/core/window/window_sdl2.py", line 405, in _mainloop
     EventLoop.idle()
   File "/usr/lib/python3/dist-packages/kivy/base.py", line 342, in idle
     self.dispatch_input()
   File "/usr/lib/python3/dist-packages/kivy/base.py", line 327, in dispatch_input
     post_dispatch_input(*pop(0))
   File "/usr/lib/python3/dist-packages/kivy/base.py", line 233, in post_dispatch_input
     listener.dispatch('on_motion', etype, me)
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/core/window/__init__.py", line 1188, in on_motion
     self.dispatch('on_touch_down', me)
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/core/window/__init__.py", line 1204, in on_touch_down
     if w.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/uix/widget.py", line 457, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/uix/widget.py", line 457, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/uix/widget.py", line 457, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy/_event.pyx", line 718, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7726)
   File "/usr/lib/python3/dist-packages/kivy/uix/behaviors/button.py", line 151, in on_touch_down
     self.dispatch('on_press')
   File "kivy/_event.pyx", line 714, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:7681)
   File "kivy/_event.pyx", line 1225, in kivy._event.EventObservers.dispatch (kivy/_event.c:13524)
   File "kivy/_event.pyx", line 1109, in kivy._event.EventObservers._dispatch (kivy/_event.c:12356)
   File "/usr/lib/python3/dist-packages/kivy/lang/builder.py", line 64, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "/home/xyzuser/project_folder/pythonprjs/pictureabarapp/picture.kv", line 37, in <module>
     on_press: root.toggle_visibility()
   File "main.py", line 35, in toggle_visibility
     self.api_input_bar.text="your api key"
 AttributeError: 'NoneType' object has no attribute 'text'

我完全按照提到的那样做了,但代码似乎不起作用。

问题是因为你在不合适的地方做赋值,api_input_bar属于Apibar,所以如果你想建立连接正确的地方在Apibar下面,因为它是它的范围:

<Apibar>:
    # Apibar Scope
    api_input_bar: api_input
    toggle_visibility_button : toggle_visibility
    BoxLayout:
        # BoxLayout scope
        orientation:"vertical"
        padding: "5dp"
        BoxLayout:
            orientation: "horizontal"
            size_hint_y: 0.5
            #some more rules for other widgets
            ToggleButton:
                id: toggle_visibility
                size_hint_x: 0.27
                text: "Hide"
                on_press: root.toggle_visibility()
                #some more rules for other widgets

在别处建立连接时,正在为 BoxLayout 创建一个新的 ObjectProperty。这可以使用以下示例进行检查:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.lang.builder import Builder

class Apibar(BoxLayout):
    api_input_bar = ObjectProperty()
    toggle_visibility_button = ObjectProperty()  

    def toggle_visibility(self):
        # self.ids.box.api_input_bar is different of self.api_input_bar
        self.ids.box.api_input_bar.text="your api key"

Builder.load_string('''
<Apibar>:
    BoxLayout:
        id: box
        orientation:"vertical"
        padding: "5dp"
        api_input_bar: api_input
        toggle_visibility_button : toggle_visibility
        BoxLayout:
            orientation: "horizontal"
            size_hint_y: 0.5
            #some more rules for other widgets
            ToggleButton:
                id: toggle_visibility
                size_hint_x: 0.27
                text: "Hide"
                on_press: root.toggle_visibility()
                #some more rules for other widgets
            TextInput:
                id: api_input
    ''')

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

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