#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