RecycleView
is giving me some trouble, especially with changing the columns to a specific size. I coded the intended column width with a GridLayout
above the RecycleView
. I also made an odd way to select the whole row when one cell is selected by using modulos. I'm not sure if this is the best way, but I would love other's opinions on this method.
I will eventually want to be able to delete the entire row, and then the selected data inside the JSON file. But for right now, I just want the widths appropriately sized.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.storage.jsonstore import JsonStore
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
kv_string = """
ScreenManager:
id: manager
Screen:
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgba: .2,.2,.5,1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
size_hint_y: .3
cols:4
MyButton:
text: 'Num'
size_hint_x: 0.5
MyButton:
text: 'Ratings'
MyButton:
text: 'Name'
size_hint_x: 2
MyButton:
text: 'Score'
on_press:
#arrange the boxing in ascending or descending order
RecycleView:
data: [{'text': str(x)} for x in app.data]
viewclass: 'SelectableLabel'
SelectableRecycleGridLayout:
cols: 4
#default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
ToggleButton:
id: toggle_button
size_hint_y: .3
text: 'Delete Selected'
state: 'normal'
on_press:
app.data = [0]
<SelectableLabel>:
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<MyButton@Button>:
background_color: 0,0,0,1
"""
class SelectableLabel(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
if super(SelectableLabel, self).on_touch_down(touch):
return True
# *** This selects the whole row *** # Not sure if this is the best way.
if self.collide_point(*touch.pos) and self.selectable:
self.parent.select_with_touch(self.index, touch)
if self.index % 4 == 0:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index + 3)
return
elif self.index % 4 == 1:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 2:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 3:
self.parent.select_with_touch(self.index - 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index - 3)
return
def apply_selection(self, rv, index, is_selected):
self.selected = is_selected
if App.get_running_app().root.ids.toggle_button.state == 'down':
print('Deleted', index) #Still need to add delete function
rv.layout_manager.clear_selection() #Not working
self.remove_widget(index) #Also not working
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
pass
class MyApp(App):
data = [] #ListProperty?
store = JsonStore('file.json')
store.put('Example: 1', value_1 = 'Rating: C', value_2 = 'Score: 10', value_3 = 'Name: Zack')
store.put('Example: 2', value_1 = 'Rating: A', value_2 = 'Score: 32', value_3 = 'Name: Pete')
store.put('Example: 3', value_1 = 'Rating: B', value_2 = 'Score: 24', value_3 = 'Name: Toby')
store.put('Example: 4', value_1 = 'Rating: D', value_2 = 'Score: 03', value_3 = 'Name: Lars')
x = 0
for rows in store.keys():
x += 1
data.append(x)
for row in store.get(rows):
data.append(store.get(rows)[row])
print(data) #shows successfully appended
def build(self):
root_widget = Builder.load_string(kv_string)
return root_widget
if __name__ == "__main__":
MyApp().run()
Kind of an ugly hack, but you can add a
refresh_view_layout
method to yourSelectableLabel
class:So, you can set the
size_hint
for eachSelectableLabel
to whatever you want. If you make thesize_hint_x
agree with thesize_hint_x
that is used for yourButton
column headers, I think you will get what you want.