【问题标题】:Kivy checkbox issue using custom widget使用自定义小部件的 Kivy 复选框问题
【发布时间】:2021-08-03 06:14:15
【问题描述】:

我是 Kivy 的新手(和一般的编程),所以忙于尝试学习一些小项目。特别是,我试图了解在 Kivy 中创建自定义小部件以减少代码并在小部件组始终一起使用时更容易(即带有 CheckBox 的标签)。

我创建了一个自定义小部件来组合标签和复选框。在此示例中,我想根据选中的复选框更改图像。

在代码中,我制作了两个版本,一个使用自定义小部件,另一个将标签和复选框分开。第二种方法有效,但自定义小部件没有错误:

 AttributeError: 'NoneType' object has no attribute 'ids'

在我从中提取这个 sn-p 的程序中,我做了另一个带有两个标签的小部件,其中一个标签是标题,另一个是通过时钟更新的。它工作正常,所以我不明白为什么会这样。

这是我的 kv 和 py 文件:

#:kivy 2.0.0

<SoundCheckBox@GridLayout>:
    cols:2
    label_text: ''
    check_state: 'normal'
    Label:
        text: self.parent.label_text
    CheckBox:
        state: self.parent.check_state
        allow_no_selection: False
        group: 'sound_option'
        on_active: app.sound_stat(self, self.active, self.parent.label_text)

<MyCheckBox@CheckBox>:
    state: 'normal'
    allow_no_selection: False
    group: 'sound_option'
    on_active: app.sound_stat_alt(self, self.active, self.label_text)

GridLayout:
    rows: 4
    Label: 
        text: 'Change Image Test'

    BoxLayout:
        orientation:'horizontal'

        SoundCheckBox:
            id: sound_on
            label_text: 'On'
            check_state: 'normal'
        SoundCheckBox:
            id: sound_dings
            label_text: 'Ding'
            check_state: 'down'
        SoundCheckBox:
            id: sound_off
            label_text: 'Off'
            check_state: 'normal'

    BoxLayout:
        orientation:'horizontal'
        Label:
            text: 'On (a)'
        MyCheckBox:
            id: sound_on
            label_text: 'On'
        Label:
            text: 'Ding (a)'
        MyCheckBox:
            id: sound_dings
            label_text: 'Ding'
        Label:
            text: 'Off (a)'
        MyCheckBox:
            id: sound_off
            label_text: 'Off'

    Image:
        id: im
        source: 'sound-On.png'

还有 Python 文件

from kivy.app import App
    
    
    class TestApp(App):
    
        def on_start(self):
            print(self.root.ids)    
    
        def sound_stat(self, instance, value, option):
            image_source = f'sound-{option}.png'
            # depending on check box is checked I want to set an image
            # print(self.root.ids) # Fails if this is not commented out
            
            self.root.ids.im.source = image_source # Fails if this is not commented out
    
            print(f'value is {value} and option is {option} so image source will be {image_source}')
    
        def sound_stat_alt(self, instance, value, option):
            image_source = f'sound-{option}.png'
            # depending on check box is checked I want to set an image
            print(self.root.ids) 
            self.root.ids.im.source = image_source
            print(f'value is {value} and option is {option} so image source will be {image_source}')
    
    if __name__ == "__main__":
        TestApp().run()

除非我在 sound_stat 方法中注释掉代码中注释的行,否则它不会运行。非常感谢任何见解。

编辑:我刚刚注意到,如果我不将复选框状态设置为“关闭”,上述代码将起作用。我尝试将另一个 CheckBox 的状态之一设置为“关闭”,但我得到了同样的错误。所以它可以工作,但我无法在 kv 文件中设置默认选择。为什么会这样? 因此,对于 kv 文件中的这段代码,如果我将所有状态都设置为“正常”,则代码将运行。一旦我将它们中的任何一个设置为“关闭”,它就会因属性错误而失败。然后我在 App 类的 start_up 方法中将默认按钮设置为“向下”。这是一个错误吗?当然这应该可以像我尝试的那样在kv文件中设置。

 SoundCheckBox:
        id: sound_on
        label_text: 'On'
        check_state: 'normal'
    SoundCheckBox:
        id: sound_dings
        label_text: 'Ding'
        check_state: 'down' # This 'down' causes the crash.
    SoundCheckBox:
        id: sound_off
        label_text: 'Off'
        check_state: 'normal'

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    问题是当您在kv 文件中设置SoundCheckBoxcheck_state 时,会触发on_active 操作。但这甚至发生在分配Approot 小部件之前。修复方法是使用 Clock.schedule_once() 之类的东西来延迟 check_state 的设置,或者只是忽略在分配 root 小部件之前对 check_state 的任何更改,如下所示:

    def sound_stat(self, instance, value, option):
        # ignore calls to this method that happen before the root widget is assigned
        if self.root is None:
            return
        image_source = f'sound-{option}.png'
        # depending on check box is checked I want to set an image
        # print(self.root.ids) # Fails if this is not commented out
    
        self.root.ids.im.source = image_source  # Fails if this is not commented out
    
        print(f'value is {value} and option is {option} so image source will be {image_source}')
    

    【讨论】:

    • 感谢您的解释。我对此很陌生,所以不明白为什么在分配根小部件之前触发 CheckBox 操作,但我只是通过在 start_up 方法中将 active 属性设置为“down”来解决这个问题。我的应用程序现在可以正常工作了。
    猜你喜欢
    • 2014-05-12
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    相关资源
    最近更新 更多