在 kivyMD 中选择 MDCheckbox 时出现应用程序错误
App error while selecting a MDCheckbox in kivyMD
我有一个 MDList
和 MDCheckbox
,我需要 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
中的 LeftCheckbox
的 state
在一个实例中被设置为 down
,则当该实例被回收到显示 data
.
中的另一个项目
解决方法是处理 data
中 LeftCheckbox
的 state
。为此,您需要能够确定 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
我有一个 MDList
和 MDCheckbox
,我需要 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
中的 LeftCheckbox
的 state
在一个实例中被设置为 down
,则当该实例被回收到显示 data
.
解决方法是处理 data
中 LeftCheckbox
的 state
。为此,您需要能够确定 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