在 kivyMD 中选择 MDCheckbox 时出现应用程序错误

App error while selecting a MDCheckbox in kivyMD

我有一个 MDListMDCheckbox,我需要 select 列表中的一些项目,但是例如当我 select 第一项时,最后一项也得到 selected,当我 select 第二项时,倒数第二项也得到 selected,反之亦然,如果我 select 最后一个元素然后第一个元素也得到 selected。这只发生在列表的第一个和最后两个元素上,当我 select 一个元素在它们之间时它工作正常。我怎样才能防止这种情况发生?

这是我的代码的一个类似示例:

from kivymd.uix.dialog import MDDialog
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.snackbar import Snackbar
from kivy.properties import ObjectProperty
from kivymd.uix.list import ILeftBodyTouch, ThreeLineListItem, ThreeLineAvatarIconListItem
from kivy.uix.recycleview import RecycleView
from kivymd.uix.selectioncontrol import MDCheckbox
from functools import partial

KV='''
WindowManager:
    #LoginWindow:
    MainWindow:
    SecondWindow:

<ListItemWithCheckbox>:

    LeftCheckbox:


<MainWindow>
    name: 'main'
    MDBoxLayout:
        orientation: 'vertical'
        MDToolbar:
            title: 'test'

        MDBoxLayout:
            orientation:'vertical'
            spacing: dp(10)
            padding: dp(20)

            RecycleView:
                id: rv
                key_viewclass: 'viewclass'
                key_size: 'height'
                bar_width: dp(10)
                RecycleBoxLayout:
                    padding: dp(10)
                    default_size: None, dp(80)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'



'''

product_dict={'name 1': (1, 2),
                'name 2': (3,4),
                'name 3':(4,2),
                'name 4':(4,2),
                'name 5':(4,2),
                'name 6':(4,2),
                'name 7':(4,2),
                'name 8':(4,2),
                'name 9':(4,2) ,
                'name 10':(4,2)}


class MainWindow(Screen):
    pass

class SecondWindow(Screen):
    pass

class WindowManager(ScreenManager):
    pass

class ListItemWithCheckbox(ThreeLineAvatarIconListItem):
    pass

class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
    pass

class MainApp(MDApp):

    def build(self):
        self.theme_cls.theme_style="Dark"
        self.theme_cls.primary_palette="Green"
        return Builder.load_string(KV)

    def on_start(self):

        self.set_list()

    def set_list(self):

        self.root.get_screen('main').ids.rv.data = []
        for key in product_dict:
            self.root.get_screen('main').ids.rv.data.append(
                {
                    "viewclass": "ListItemWithCheckbox",
                    "text": key,
                    "secondary_text": f'Item 1: {product_dict[key][0]}',
                    "tertiary_text": f'Item 2: {product_dict[key][1]}',
                    "on_press": partial(self.action, key)
                }
            )

    def action(self, instance):
        print(instance)

MainApp().run()

因为 RecycleView 回收 viewclass,在 viewclass 中设置的属性将反映在 viewclass 的回收实例中,除非您明确处理这些属性.因此,如果 ListItemWithCheckbox 中的 LeftCheckboxstate 在一个实例中被设置为 down,则当该实例被回收到显示 data.

中的另一个项目

解决方法是处理 dataLeftCheckboxstate。为此,您需要能够确定 data 中的哪个项目当前与 LeftCheckbox.

相关联

一种方法是将属性添加到 ListItemWithCheckbox:

class ListItemWithCheckbox(ThreeLineAvatarIconListItem):
    selected = BooleanProperty(False)  # is this checkbox down
    data_index = NumericProperty(-1)  # index into the RV data

    def state_changed(self):
        self.selected = self.ids.lcb.state == 'down'  # set the selected property

        # save the change to the data
        rv = MDApp.get_running_app().root.get_screen('main').ids.rv
        rv.data[self.data_index]['selected'] = self.selected

然后调整set_list()方法来初始化新的属性:

def set_list(self):

    self.root.get_screen('main').ids.rv.data = []
    index = 0
    for key in product_dict:
        self.root.get_screen('main').ids.rv.data.append(
            {
                "viewclass": "ListItemWithCheckbox",
                "text": key,
                "secondary_text": f'Item 1: {product_dict[key][0]}',
                "tertiary_text": f'Item 2: {product_dict[key][1]}',
                "on_press": partial(self.action, key),
                "selected": False,
                "data_index": index
            }
        )
        index += 1

并在kv中修改ListItemWithCheckbox:

<ListItemWithCheckbox>:
    LeftCheckbox:
        id: lcb
        on_press: root.state_changed()  # save change to the data
        state: 'down' if root.selected else 'normal' #  get state from the "selected" property