Hi,
I have two RecycleViews, and my goal is to be able to move items between these.
At the beginning List 1 is populated with values 0,1,2 , when I select a value it is added to other list, I click on every item of List 1,
so List2 is populated also with 0,1,2, this works fine.
When I click on List2: I want to delete the selected ITEM of this list, which does not work as expected. Depending on the selection multiple items are deleted, to be precise the selected and all subsequent items, based on index, are removed from the list.
After that, it is not possible to add new items to List2.
Based on the log, I assume, that I have to handle the is_selected of the items in List2, but I am not sure how to do that.
Thanks for any help.
Steps:
1 :SelectableLabel: choose values 2,1,0
2: SelectableLabel_selected: select 2
3: SelectableLabel:: select 2
Log:
#startup
SelectableLabel: index: 0, is_selected False
SelectableLabel: index: 1, is_selected False
SelectableLabel: index: 0, is_selected False
SelectableLabel: index: 1, is_selected False
SelectableLabel: index: 2, is_selected False
SelectableLabel: index: 0, is_selected False
SelectableLabel: index: 1, is_selected False
SelectableLabel: index: 2, is_selected False
SelectableLabel: index: 2, is_selected True
#Step 1:
# 2 selected
SelectableLabel: index: 2, is_selected True
SelectableLabel_Selected: index: 0, is_selected False
#1 selected
SelectableLabel: index: 1, is_selected True
SelectableLabel_Selected: index: 0, is_selected False
SelectableLabel_Selected: index: 1, is_selected False
#0 selected
SelectableLabel: index: 1, is_selected False
SelectableLabel: index: 0, is_selected True
SelectableLabel_Selected: index: 0, is_selected False
SelectableLabel_Selected: index: 1, is_selected False
SelectableLabel_Selected: index: 2, is_selected False
#Step2: This step deletes all data as index 0 is selected everytime
SelectableLabel_Selected: index: 0, is_selected True
RV_selected: remove_data executed with value: {'text': '2'}
SelectableLabel_Selected: index: 0, is_selected True
RV_selected: remove_data executed with value: {'text': '1'}
SelectableLabel_Selected: index: 1, is_selected False
SelectableLabel_Selected: index: 0, is_selected True
RV_selected: remove_data executed with value: {'text': '0'}
#Step 3: Select 2 in first list:
SelectableLabel: index: 0, is_selected False
SelectableLabel: index: 2, is_selected True
SelectableLabel_Selected: index: 0, is_selected True
RV_selected: remove_data executed with value: {'text': '2'}
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.core.window import Window
Window.clearcolor = (0, 0.5, 0.5, 1)
Builder.load_string('''
<AppRoot>:
orientation:"horizontal"
rv:rv
rv_selected:rv_selected
BoxLayout:
orientation:"vertical"
size_hint:1,1
Label:
text:"SelectableLabel:"
size_hint:1,0.2
RV:
id:rv
size_hint:1,0.8
BoxLayout:
size_hint:1,1
orientation:"vertical"
Label:
text:"SelectableLabel_Selected:"
size_hint:1,0.2
RV_Selected:
id:rv_selected
size_hint:1,0.8
<RV>:
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
touch_multiselect: False
<RV_Selected>:
viewclass: 'SelectableLabel_Selected'
SelectableRecycleBoxLayout_Selected:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
touch_multiselect: False
''')
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableRecycleBoxLayout_Selected(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_data_changed(self):
pass
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
print("SelectableLabel: index: {}, is_selected {}".format(index, is_selected))
if is_selected:
app = App.get_running_app()
app.root.rv_selected.data.append(rv.data[index])
else:
pass
#print("SelectableLabel: selection removed for {0}".format(rv.data[index]))
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(3)]
def add_data(self,value):
self.data.append(value)
print("RV: add_data executed with value: {}".format(value))
class SelectableLabel_Selected(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel_Selected, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel_Selected, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
print("SelectableLabel_Selected: index: {}, is_selected {}".format(index,is_selected))
self.selected = is_selected
if is_selected:
rv.remove_data(rv.data[index])
#print("SelectableLabel_Selected: selection changed to {0}".format(rv.data[index]))
else:
pass
#print("SelectableLabel_Selected: selection removed for {0}".format(rv.data[index]))
class RV_Selected(RecycleView):
def __init__(self, **kwargs):
super(RV_Selected, self).__init__(**kwargs)
def remove_data(self,value):
"""value of dictionary, eg. 3 """
new_selected_dict = [elem for elem in self.data if value["text"] not in elem["text"]]
self.data=new_selected_dict
print("RV_selected: remove_data executed with value: {}".format(value))
class AppRoot(BoxLayout):
pass
class TestApp(App):
def build(self):
return AppRoot()
if __name__ == '__main__':
TestApp().run()