\n
I wanted the Row to expand, so the Label would appear below the Button, each at normal size.
\nAs I continued to play with it, I realized that it was actually inconsistent in its behavior:\n
One time the Label would not be shown at all, but the button would be twice as high. Another time it would appear as I had hoped! I have no idea how to guarantee consistent, hoped-for behavior.
\nI tried making changes to the code...
\nI made a small change at the App level to hang on to the main layout, so I could get access to the RecycleView later:
\nclass TestApp(App):\n testLayout = ObjectProperty(None)\n\n def build(self):\n testLayout = Test()\n return testLayout\n
\nThen I changed the code for expanding the Row:
\ndef expand(self):\n if self.is_expanded:\n self.is_expanded = False\n self.remove_widget(self.label)\n self.height -= self.label.height\n print(f"Row with heading '{self.heading}' has been contracted!")\n else:\n self.is_expanded = True\n self.label = Label(text='Expanded data ...', markup=True, size_hint_y=None, height=dp(50))\n self.add_widget(self.label)\n self.height += self.label.height\n print(f"Row with heading '{self.heading}' has been expanded!")\n print(f"Label height '{self.label.height}' Row height '{self.height}' ")\n # Use Clock to schedule refresh after the layout update\n Clock.schedule_once(self.refresh_view, 0)\n\ndef refresh_view(self, *args):\n rv = self.get_recycleview_parent()\n if rv:\n rv.refresh_from_data()\n\ndef get_recycleview_parent(self):\n parent = self.parent\n while parent and not isinstance(parent, RecycleView):\n parent = parent.parent\n return parent\n
\nI tried adding the label height to the Row height when expanded, but subtracting the label height from the Row height when contracted. Then I got the RecycleView from the main layout and called refresh_from_data() to readjust everything to the new reality.
\nThat didn't work. I couldn't get the RecycleView that way.
\nThat's when I added the call to get_recycleview_parent() to get the RecycleView. Now, clicking on a row causes multiple, random rows to expand, inconsistently, and the program hangs.
\nCan anyone offer suggestions on how to get the desired behavior (in contrast to the ineffective guesses from Copilot)?
\n","author":{"@type":"Person","name":"Todd Hoatson"},"upvoteCount":0,"answerCount":0,"acceptedAnswer":null}}Reputation: 364
I wanted to use the Kivy Accordion widget in my python app, but I couldn't get it to work right - the accordion items would expand or contract to exactly fill the space in the window. That's when I realized I had a bigger problem: the number of accordion items could increase indefinitely, but my accordion had no scroll bar. So, after some searching, I found the RecycleView stuff in Kivy. After looking at the online documentation, as well as the demo code in \Python311\share\kivy-examples\widgets\recycleview, I decided to grab basic_data.py and make some modifications.
Here's my code:
from random import sample, randint
from string import ascii_lowercase
from datetime import date
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.recycleview.views import RecycleKVIDsDataViewBehavior
kv = """
<Row>:
heading: ''
BoxLayout:
orientation: 'horizontal'
Button:
background_normal: ''
background_color: 0.3, 0.4, 0.3, 1
text: root.heading
on_press: root.expand()
<Test>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'heading'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new heading'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
"""
Builder.load_string(kv)
class Row(RecycleKVIDsDataViewBehavior, BoxLayout):
is_expanded = ObjectProperty(None)
heading = StringProperty(None)
label = ObjectProperty(None)
orientation = 'vertical'
def expand(self):
print(f"Row with heading '{self.heading}' has been expanded!")
if self.is_expanded:
self.is_expanded = False
self.remove_widget(self.label)
self.height -= self.label.height
else:
self.is_expanded = True
self.label = Label(text='Expanded data ...', markup=True)
self.add_widget(self.label)
self.height += self.label.height
class Test(BoxLayout):
def populate(self):
self.rv.data = [
{'heading': date.today().__str__() + ' ' + str(randint(0, 2000))}
for x in range(50)]
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['heading'])
def clear(self):
self.rv.data = []
def insert(self, heading):
self.rv.data.insert(0, {
'name.text': heading or 'default heading', 'heading': 'unknown'})
def update(self, heading):
if self.rv.data:
self.rv.data[0]['name.text'] = heading or 'default new heading'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class TestApp(App):
def build(self):
return Test()
# def expand(self, row):
# row.expand()
if __name__ == '__main__':
TestApp().run()
When I ran the code, I was able to populate the RecycleView. I had changed the definition of Row to include a button for expanding and contracting an individual Accordion item. When expanded, a Label widget is added to the Row. When contracted, the Label is removed. So far so good...
But when expanded, the Row item did not increase in height - at least at first. So the Button and Label simply became more compact:
I wanted the Row to expand, so the Label would appear below the Button, each at normal size.
As I continued to play with it, I realized that it was actually inconsistent in its behavior:
One time the Label would not be shown at all, but the button would be twice as high. Another time it would appear as I had hoped! I have no idea how to guarantee consistent, hoped-for behavior.
I tried making changes to the code...
I made a small change at the App level to hang on to the main layout, so I could get access to the RecycleView later:
class TestApp(App):
testLayout = ObjectProperty(None)
def build(self):
testLayout = Test()
return testLayout
Then I changed the code for expanding the Row:
def expand(self):
if self.is_expanded:
self.is_expanded = False
self.remove_widget(self.label)
self.height -= self.label.height
print(f"Row with heading '{self.heading}' has been contracted!")
else:
self.is_expanded = True
self.label = Label(text='Expanded data ...', markup=True, size_hint_y=None, height=dp(50))
self.add_widget(self.label)
self.height += self.label.height
print(f"Row with heading '{self.heading}' has been expanded!")
print(f"Label height '{self.label.height}' Row height '{self.height}' ")
# Use Clock to schedule refresh after the layout update
Clock.schedule_once(self.refresh_view, 0)
def refresh_view(self, *args):
rv = self.get_recycleview_parent()
if rv:
rv.refresh_from_data()
def get_recycleview_parent(self):
parent = self.parent
while parent and not isinstance(parent, RecycleView):
parent = parent.parent
return parent
I tried adding the label height to the Row height when expanded, but subtracting the label height from the Row height when contracted. Then I got the RecycleView from the main layout and called refresh_from_data() to readjust everything to the new reality.
That didn't work. I couldn't get the RecycleView that way.
That's when I added the call to get_recycleview_parent() to get the RecycleView. Now, clicking on a row causes multiple, random rows to expand, inconsistently, and the program hangs.
Can anyone offer suggestions on how to get the desired behavior (in contrast to the ineffective guesses from Copilot)?
Upvotes: 0
Views: 19