from kivy.uix.modalview import ModalView
from kivy.uix.screenmanager import Screen
from kivymd.app import MDApp
from kivy.metrics import dp
from kivy.lang.builder import Builder
KV = """
<ImgCard@ButtonBehavior+BoxLayout>
path: ""
orientation: "vertical"
size_hint_y: None
Image:
source: root.path
size_hint_y: .9
MDCheckbox:
<Gallery>
orientation: 'vertical'
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
RecycleView:
id: img_base
viewclass: "ImgCard"
canvas.before:
#$#Color:
#$rgba: (.4, .4, .4, .7)
Rectangle:
size: self.size
pos: self.pos
RecycleGridLayout:
spacing: 10
cols: 3
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True """
class ImageManager(ModalView):
pass
class Gallery(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.manager_list = []
self.dir = os.getcwd()
self.available_image_format = ['.png', '.jpg', '.jpeg', '.bmp'] # etc
def load_images(self):
if not self.manager_list:
for image in os.listdir(self.dir):
target_filename, target_file_extension = os.path.splitext(image)
if target_file_extension in self.available_image_format:
path_to_image = os.path.join(self.dir, image)
self.manager_list.append(
{
"ImgCard": "ImageManager",
"path": path_to_image,
"height": dp(200),
}
)
self.ids.img_base.data = self.manager_list
self.images=[self.dir]
class GalleryApp(MDApp):
def build(self):
Builder.load_string(KV)
return Gallery()
def on_start(self):
self.root.load_images()
if __name__=='__main__':
GalleryApp().run()
How to link checkbox in gallery for also multiple select in kivy. Can anyone help this?
If you are using MDCheckbox
in a RecycleView
, then you should include the state
of that MDCheckbox
in the data
. If you don't do that, then the RecyclView
doesn't know about the state
of the MDCheckbox
and when an MDCheckbox
gets recycled, its state
will be whatever it was last time it was used.
To accomplish that, first modify your kv
rule for ImgCard
:
<ImgCard@BoxLayout>
path: ""
selected: False # added to indicate selection
index: -1 # added to enable accessing this item in the data
orientation: "vertical"
size_hint_y: None
Image:
source: root.path
size_hint_y: .9
MDCheckbox:
id: cb
state: 'down' if root.selected else 'normal'
on_release: app.root.adjust_data(root)
Note that the ButtonBehavior
is not necessary.
Then, modify the initial data
to initialize the new properties:
def load_images(self):
count = 0
if not self.manager_list:
for image in os.listdir(self.dir):
target_filename, target_file_extension = os.path.splitext(image)
if target_file_extension in self.available_image_format:
path_to_image = os.path.join(self.dir, image)
self.manager_list.append(
{
"ImgCard": "ImageManager",
"path": path_to_image,
"height": dp(200),
"selected": False,
"index": count
}
)
count += 1
self.ids.img_base.data = self.manager_list
self.images = [self.dir]
And add a method in the Gallery
class to update the data
when a MDCheckbox
is changed:
def adjust_data(self, imgcard):
rv = self.ids.img_base
rv.data[imgcard.index]['selected'] = imgcard.ids.cb.state == 'down'
imgcard.ids.cb.state = 'normal'
rv.refresh_from_data()
To remove the selected items, you can add a Button
in your <Gallery>
rule that calls:
def delete(self, instance):
rv = self.ids.img_base
deleted = False
for i in range(len(rv.data) - 1, -1, -1):
item = rv.data[i]
if item['selected']:
del rv.data[i]
deleted = True
if deleted:
self.adjust_indices()
Since deleting any items will upset the index
property of items in the data
, another method is required to adjust the index
properties:
def adjust_indices(self):
# adjust index values to account for removd items
rv = self.ids.img_base
index = 0
for item in rv.data:
item['index'] = index
index += 1