【问题标题】:Kivy ObjectProperty is None when I'm expecting a TextInput instance, what am I missing?当我期待 TextInput 实例时,Kivy ObjectProperty 为 None,我错过了什么?
【发布时间】:2021-09-13 17:42:29
【问题描述】:

我正在尝试使用DropDown 构建一个下拉列表,该小部件的行为应该类似于在 Windows 文件资源管理器中看到的。

我有一个TextInput 和一个Button,我将DropDown 与它们相关联。当我运行以下代码时,出现错误:

Exception has occurred: AttributeError
'NoneType' object has no attribute 'text'
  File "C:\Users\hanne\Documents\_Educational\_Learning\Python\Kivy\DropDown\B.ii\main.py", line 34, in on_select
    setattr(self.user_choice, 'text', data)
  File "C:\Users\hanne\Documents\_Educational\_Learning\Python\Kivy\DropDown\B.ii\main.py", line 45, in on_touch_down
    self.dropdown.select(self.text)
  File "C:\Users\hanne\Documents\_Educational\_Learning\Python\Kivy\DropDown\B.ii\main.py", line 69, in <module>
    MyApp().run()

main.py

import kivy
kivy.require('2.0.0')

from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import ObjectProperty

class TextEntryDropDown(BoxLayout):

    user_choice = ObjectProperty(None)
    drop_button = ObjectProperty(None)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.dropdown = DropDownList(self.user_choice)

        for item in ['Option 1', 'Option 2', 'Option 3']:
            label = DropDownItem(self.dropdown, text=item, size_hint_y=None, height=30)
            self.dropdown.add_widget(label)


class DropDownList(DropDown):

    def __init__(self, user_choice, **kwargs):
        super().__init__(**kwargs)
        self.user_choice = user_choice

    def on_select(self, data):
        setattr(self.user_choice, 'text', data)


class DropDownItem(Label):

    def __init__(self, dropdown, **kwargs):
        super().__init__(**kwargs)
        self.dropdown = dropdown

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            self.dropdown.select(self.text)
        return super().on_touch_down(touch)


class DropButton(Button):
    
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            dropdown = self.parent.dropdown
            dropdown.open(self)
        return super().on_touch_down(touch)


class MainApp(AnchorLayout):
    pass


class MyApp(App):

    def build(self):
        return MainApp()


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

my.kv

<MainApp>:
    anchor_x: 'left'
    anchor_y: 'top'
    TextEntryDropDown:
        

<TextEntryDropDown>
    size_hint_y: None
    height: 30

    user_choice: user_choice
    drop_button: drop_button

    TextInput:
        id: user_choice
        text: 'Select an option..'
        size_hint: (None, None)
        height: 30
        width: root.width - drop_button.width

    DropButton:
        id: drop_button
        size_hint: (None, None)
        height: user_choice.height
        width: user_choice.width

我试图追查为什么user_choiceNone,我希望它是对my.kv 中定义的TextInput 的引用。知道为什么会这样吗?我不能指望它。

谢谢!

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    问题是TextEntryDropDownObjectPropertiesuser_choicedrop_button)在TextEntryDropDown__init__()方法中尚不可用。一种解决方法是在创建DropDownList 时传递对TextEntryDropDown 的引用,而不是传递尚未定义的user_choice。像这样:

    class TextEntryDropDown(BoxLayout):
        user_choice = ObjectProperty(None)
        drop_button = ObjectProperty(None)
    
        def __init__(self, **kwargs):
            print('TextEntryDropDown.__init__(), self.user_choice =', self.user_choice)
            super().__init__(**kwargs)
    
            self.dropdown = DropDownList(self)  # pass reference to this TextEntryDropDown
    
            for item in ['Option 1', 'Option 2', 'Option 3']:
                label = DropDownItem(self.dropdown, text=item, size_hint_y=None, height=30)
                self.dropdown.add_widget(label)
    

    然后在DropDownList:

    class DropDownList(DropDown):
    
        def __init__(self, ted, **kwargs):
            super().__init__(**kwargs)
            self.textEntryDropDown = ted  # save reference to the TextEntryDropDown
            # self.user_choice = user_choice
    
        def on_select(self, data):
            self.textEntryDropDown.user_choice.text = data  # use TextEntryDropDown to access now available user_choice ObjectProperty
            # setattr(self.user_choice, 'text', data)
    

    【讨论】:

    • 啊!我曾假设父实例总是会被完全实例化,而我只能访问这些对象。谢谢你的澄清,我不明白
    【解决方案2】:

    问题是您在 .kv 文件的第 20 行创建了一个无限循环。在第 26 行中,您将 drop_button 宽度定义为 user_choice.width,然后在第 20 行中,您将 user_choice 宽度定义为 root.width - drop_button.width

    要修复错误,请更改以下内容:

    width: root.width - drop_button.width
    

    width: drop_button.width
    

    【讨论】:

      猜你喜欢
      • 2021-11-19
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-21
      • 2020-09-02
      • 1970-01-01
      相关资源
      最近更新 更多