Reputation: 689
I’m fairly new in python but a complete beginner with Kivy. I find the documentation around Kivy to be hard to interpret at least for me. So far I have been able to create a RecycleView where I am able to add, remove and change data. Ideally, I want to be able to have as many columns as I want but all the data on each row belongs together. Hence if I select one I want to highlight all items on that row. I have tried with togglebutton but without any success. I simply don’t know how I can access each individual togglebutton in the RecycleView through ids or some other method. If I could access each togglebutton individually I could simply change its state to be equal to ‘Down’. So far I have only been able to find which row the user selected (however not so elegantly). I managed this by calculating the number of buttons per row and comparing this against the index of the selected button.
Here is an example where I'm experimenting, usually I prefer using the .kv file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.recycleview.views import RecycleDataViewBehavior
class MyButton(RecycleDataViewBehavior, ToggleButton):
index = None
def refresh_view_attrs(self, rv, index, data):
""" Catch and handle the view changes """
self.index = index
return super(MyButton, self).refresh_view_attrs(
rv, index, data)
class TestRecycleView(RecycleView):
items_per_row = 3
selected_data = None
selected_row = None
def find_row(self, instance):
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
KV = '''
<MyButton>:
on_release:
app.root.find_row(self)
TestRecycleView:
data: [{'text': str(x)} for x in range(21)]
viewclass: 'MyButton'
id: rv_controller
target_id: None
RecycleGridLayout:
cols: 3
default_size_hint: 1, None
orientation: 'vertical'
key_selection: 'selectable'
default_size: None, dp(26)
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
'''
class Test(App):
def build(self):
root = Builder.load_string(KV)
# root.data = items
return root
Test().run()
Since I have been able to calculate what row got selected by the user I can also calculate what data in the RecycleView that is being selected. However, I would like a neat visual representation for this kind of row selection.
Would greatly appreciate some help.
Upvotes: 0
Views: 816
Reputation: 38992
You can add a hack to your find_row()
method to set the state of all the buttons in a row. This method sets them to agree with the state of the Button
instance selected, so you can also unselect.
def find_row(self, instance):
rgl = self.ids.gl
num_buttons = len(rgl.children)
num_rows = num_buttons // self.items_per_row
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
index1 = (num_rows - self.selected_row + 1) * self.items_per_row - 1
index2 = index1 - self.items_per_row
state = instance.state
for index in range(index1, index2, -1):
rgl.children[index].state = state
This also requires setting the id of the RecycleGridLayout
as:
id: gl
The Buttons
are children of the RecycleGridLayout
, so that can be used to get the total number of Buttons
. And the index into the children
list is the opposite of what you would expect. That is that the Button
labelled 0
is index 20
and the Button
labelled 20
is index 0
. So the calculation of index1
uses that knowledge to determine the index of the left-most Button
in the selected row. Then the right-most Button
in the selected row will be index - 2
. The range(inde1, index2, -1)
steps through the Buttons
in the selected row. Since find_row()
is called on_release
, the state
of the instance
is already toggled, so its state
can be used to set the state
of the other Buttons
in the row.
Upvotes: 1