'Kivy RecycleView not showing data after moving into a screen
I've modified a Kivy RecycleView example and put it into a screen with menu, but now it's showing empty pages instead of data. I suspect the root have changed but I'm unable to connect the RecycleView to the correct source.
To be honest I think I've to work more on learning how to proper link between different objects.
My modified version that has the issue:
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
KV = """
<SomeMenu_ActionBar@ActionBar>:
ActionView:
id: ActionView
HiddenIcon_ActionPrevious:
ActionButton:
text: 'Stop'
on_release: app.stop()
<HiddenIcon_ActionPrevious@ActionPrevious>:
<MainBox>:
orientation: 'vertical'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
# source: 'data/background.png'
MyManager:
id: sm
RVScreen:
id: rvscreen
SomeMenu_ActionBar:
id: ActionBar
<RecycleItem>:
orientation: 'horizontal'
Label:
text: root.label_text
TextInput:
text: root.input_text
on_text: root.set_text(self.text)
RecycleView:
data: app.data
viewclass: 'RecycleItem'
RecycleBoxLayout:
spacing: 10
default_size: None, dp(80)
default_size_hint: 1, None
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
<RVScreen>:
id: "rvscreen"
BoxLayout:
orientation: "vertical"
RecycleView:
Button:
text: 'Previous screen'
size_hint: None, None
size: 150, 50
on_release: root.manager.current = root.manager.previous()
"""
class RecycleItem(RecycleDataViewBehavior, BoxLayout):
owner = ObjectProperty()
index = NumericProperty(0)
input_text = StringProperty()
label_text = StringProperty()
def set_text(self, text):
if self.owner is not None:
self.owner.data[self.index]['input_text'] = text
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class MainBox(BoxLayout):
"""Mainbox under MainApp
It contains the ScreenManager
"""
pass
class RVScreen(Screen):
pass
class MyManager(ScreenManager):
"""The screen manager that handles app screens
"""
pass
class Test(App):
data = ListProperty()
def build(self):
self.data = [{'label_text': "Label "+str(x), "input_text": "Input "+str(x), 'owner': self} for x in range(20)]
Builder.load_string(KV)
return MainBox()
Test().run()
Original working example:
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.lang.builder import Builder
KV = """
<RecycleItem>:
orientation: 'horizontal'
Label:
text: root.label_text
TextInput:
text: root.input_text
on_text: root.set_text(self.text)
RecycleView:
data: app.data
viewclass: 'RecycleItem'
RecycleBoxLayout:
spacing: 10
default_size: None, dp(80)
default_size_hint: 1, None
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
<RVScreen>:
BoxLayout:
orientation: "vertical"
RecycleView:
Button:
text: 'Previous screen'
size_hint: None, None
size: 150, 50
on_release: root.manager.current = root.manager.previous()
"""
class RecycleItem(RecycleDataViewBehavior, BoxLayout):
owner = ObjectProperty()
index = NumericProperty(0)
input_text = StringProperty()
label_text = StringProperty()
def set_text(self, text):
if self.owner is not None:
self.owner.data[self.index]['input_text'] = text
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class Test(App):
data = ListProperty()
def build(self):
self.data = [{'label_text': "Label "+str(x), "input_text": "Input "+str(x), 'owner': self} for x in range(20)]
return Builder.load_string(KV)
Test().run()
Solution 1:[1]
You can define the root widget in several ways.
If you have the build method in the App's subclass and it returns some Widget, it will be set as the root widget. Or you can assign the root to the kv-rule by loading it there etc.
In this case in your kv-rule you defined RecycleView as the root widget but you haven't used it in build to set it as the root.
Meanwhile you returned MainBox from the method build so it will be used as root widget. Again you loaded the kv-rule there so the design etc. will be applied to this root widget.
Now in order to add RecycleView to RVScreen (as you mentioned in comment) and set MainBox as root widget (as you did already) you can modify your kvlang as follows:
<SomeMenu_ActionBar@ActionBar>:
ActionView:
id: ActionView
HiddenIcon_ActionPrevious:
ActionButton:
text: 'Stop'
on_release: app.stop()
<HiddenIcon_ActionPrevious@ActionPrevious>:
<MainBox>:
orientation: 'vertical'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
# source: 'data/background.png'
MyManager:
id: sm
RVScreen:
id: rvscreen
SomeMenu_ActionBar:
id: ActionBar
<RecycleItem>:
orientation: 'horizontal'
Label:
text: root.label_text
TextInput:
text: root.input_text
on_text: root.set_text(self.text)
<RVScreen>:
id: "rvscreen"
BoxLayout:
orientation: "vertical"
RecycleView:
data: app.data
viewclass: 'RecycleItem'
RecycleBoxLayout:
spacing: 10
default_size: None, dp(80)
default_size_hint: 1, None
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
Button:
text: 'Previous screen'
size_hint: None, None
size: 150, 50
on_release: root.manager.current = root.manager.previous()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ApuCoder |
