Ошибка приложения при выборе флажка MDCheckbox в KivyMD

#python #python-3.x #kivy #kivy-language #kivymd

#питон #python-3.x #киви #киви-язык #кивимд

Вопрос:

У меня есть MDList с MDCheckbox , и мне нужно выбрать некоторые элементы списка, но, например, когда я выбираю первый элемент, также выбирается последний, и когда я выбираю второй элемент, также выбирается предпоследний элемент, и наоборот, если я выбираю последний элемент, то также выбирается первый. Это происходит только с первым и последними двумя элементами списка, когда я выбираю элемент между ними, он работает нормально. Как я могу предотвратить это?

Вот аналогичный пример моего кода:

 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:  lt;ListItemWithCheckboxgt;:   LeftCheckbox:   lt;MainWindowgt;  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()  

Ответ №1:

Поскольку RecycleView повторяет viewclass , свойства, которые устанавливаются в viewclass , будут отражены в переработанных экземплярах viewclass , если вы явно не обработаете эти свойства. Таким образом, если state LeftCheckbox в вашем ListItemWithCheckbox экземпляре будет установлено значение down в одном экземпляре, оно останется таким же, как down и при переработке этого экземпляра для отображения другого элемента из data .

Решение состоит в том, чтобы справиться state LeftCheckbox с тем, что находится в вашем data . Для этого вам необходимо определить, какой элемент в data настоящее время связан с a 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 :

 lt;ListItemWithCheckboxgt;:  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