Reputation: 93
I want to put the data of a (csv-)table into a kivy recycleview.
I managed to insert multiple columns with one row, if i assign a fixed text to the Labels in the kv, but i can't get it to fill the labels with data from a dictionary list. This is the code so far, that i use to test the concept:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
import csv
items = [{'SP1': 'Artikelnummer', 'SP2': 'Name', 'SP3': 'Groesse'},
{'SP1': '510001', 'SP2': 'Big Pump', 'SP3': '1.50 L'},
{'SP1': '523001', 'SP2': 'Leonie Still', 'SP3': '1.50 L'},
{'SP1': '641301', 'SP2': 'Cola Mix', 'SP3': '1.50 L'}
]
class Tabelle(BoxLayout):
def __init__(self, **kwargs):
super(Tabelle, self).__init__(**kwargs)
def insert_SP(self, data):
for i in data:
self.spalte1_SP = i['SP1']
#print(self.spalte1_SP)
self.spalte2_SP = i['SP2']
self.spalte3_SP = i['SP3']
Builder.load_string('''
<Tabelle>:
orientation: 'horizontal'
spalte1_SP: 'spalte1'
spalte2_SP: 'spalte2'
spalte3_SP: 'spalte3'
Label:
id: Spalte1
text: root.spalte1_SP
Label:
id: Spalte2
text: root.spalte2_SP
Label:
id: Spalte3
text: root.spalte3_SP
<RV>:
viewclass: 'Tabelle'
RecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
#self.data = []
x = Tabelle()
x.insert_SP(items)
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
I expect to see the data from items in 3 columns, but they stay empty for some reason.
Upvotes: 3
Views: 2654
Reputation: 1934
Based on the previous solution, here's a code whose interpretation is much easier. Additionally, one of the column is a checkbox.
Python file:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
# data
items = [{'number': '510001', 'name': 'Big Pump', 'size': '1.50 L', 'in_stock': True},
{'number': '523001', 'name': 'Leonie Still', 'size': '1.60 L', 'in_stock': False},
{'number': '641301', 'name': 'Apple Mix', 'size': '1.30 L', 'in_stock': True},
{'number': '681301', 'name': 'Orange Mix', 'size': '1.40 L', 'in_stock': True}
]
class MultiFieldLine(BoxLayout):
# class layout defined in kv file
pass
class AppGUI(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.rv.data = [{'label_1': str(x['number']), 'label_2': str(x['name']), 'label_3': str(x['size']), 'checkbox_1': x['in_stock']} for x in items]
class ExploreRecycleViewMultipleFieldApp(App):
def build(self):
return AppGUI()
if __name__ == '__main__':
ExploreRecycleViewMultipleFieldApp().run()
KV file:
<MultiFieldLine>:
orientation: 'horizontal'
label_1: ''
label_2: ''
label_3: ''
checkbox_1: False
Label:
text: root.label_1
Label:
text: root.label_2
Label:
text: root.label_3
CheckBox:
active: root.checkbox_1
<AppGUI>: # inherit from GridLayout
rv: rv_id
cols: 1
rows: 2
GridLayout: # col titles
cols: 4
rows: 1
size_hint_y: 0.04
Label:
text: 'Number'
Label:
text: 'Name'
Label:
text: 'Size'
Label
text: 'In stock'
GridLayout: # data
cols: 1
rows: 1
size_hint_y: 0.96
RecycleView:
id: rv_id
viewclass: 'MultiFieldLine'
RecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
The version below adds row selection as well as a larger label width for the name column and a method in the gui class called each time a line is selected.:
Python file:
from kivy.app import App
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
# data
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
items = [{'number': '510001', 'name': 'Big Pump', 'size': '1.50 L', 'in_stock': True},
{'number': '523001', 'name': 'Leonie Still very, very,very long, long name', 'size': '1.60 L', 'in_stock': False},
{'number': '641301', 'name': 'Apple Mix', 'size': '1.30 L', 'in_stock': True},
{'number': '681301', 'name': 'Orange Mix', 'size': '1.40 L', 'in_stock': True}
]
class MultiFieldLine(RecycleDataViewBehavior, BoxLayout):
''' class layout defined in kv file '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.rv = rv
self.appGUI = rv.appGUI
self.index = index
return super(MultiFieldLine, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(MultiFieldLine, 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):
# instance variable used in .kv file to change the selected item
# color !
self.selected = is_selected
if is_selected:
self.appGUI.outputSelectedData(rv.data[index])
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
# required to authorise unselecting a selected item
touch_deselect_last = BooleanProperty(True)
class AppGUI(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.rv.data = [{'label_1': str(x['number']), 'label_2': str(x['name']), 'label_3': str(x['size']), 'checkbox_1': x['in_stock']} for x in items]
def outputSelectedData(self, data):
# method called when a line is selected
print(data)
class ExploreRecycleViewMultipleFieldBoxLayoutApp(App):
def build(self):
return AppGUI()
if __name__ == '__main__':
ExploreRecycleViewMultipleFieldBoxLayoutApp().run()
KV file:
<MultiFieldLine>: # inherit from RecycleDataViewBehavior and BoxLayout
orientation: 'horizontal'
label_1: ''
label_2: ''
label_3: ''
checkbox_1: False
# add selection background
canvas.before:
Color:
rgba: (1, 0, 0, 1) if self.selected else (.0, 0.9, .1, .3)
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: (0, 0.9, .1, .3)
Label:
size_hint_x: 0.1
text: root.label_1
Label:
size_hint_x: 0.7
text: root.label_2
Label:
size_hint_x: 0.1
text: root.label_3
CheckBox:
size_hint_x: 0.1
active: root.checkbox_1
<AppGUI>: # inherit from GridLayout
rv: rv_id
cols: 1
rows: 2
GridLayout: # col titles
cols: 4
rows: 1
size_hint_y: 0.04
Label:
size_hint_x: 0.1
text: 'Number'
Label:
size_hint_x: 0.7
text: 'Name'
Label:
size_hint_x: 0.1
text: 'Size'
Label
size_hint_x: 0.1
text: 'In stock'
GridLayout: # data
cols: 1
rows: 1
size_hint_y: 0.96
RecycleView:
id: rv_id
appGUI: root
viewclass: 'MultiFieldLine'
SelectableRecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Upvotes: 2
Reputation: 16031
It is empty because data
was not populated.
class Tabelle()
pass
into class Tabelle()
__init__()
of class RV()
self.data = [{'spalte1_SP': str(x['SP1']), 'spalte2_SP': str(x['SP2']), 'spalte3_SP': str(x['SP3'])} for x in items]
The view is generatad by processing the data, essentially a list of dicts, and uses these dicts to generate instances of the viewclass as required.
data
The data used by the current view adapter. This is a list of dicts whose keys map to the corresponding property names of the viewclass.
data is an AliasProperty that gets and sets the data used to generate the views.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
items = [{'SP1': 'Artikelnummer', 'SP2': 'Name', 'SP3': 'Groesse'},
{'SP1': '510001', 'SP2': 'Big Pump', 'SP3': '1.50 L'},
{'SP1': '523001', 'SP2': 'Leonie Still', 'SP3': '1.50 L'},
{'SP1': '641301', 'SP2': 'Cola Mix', 'SP3': '1.50 L'}
]
class Tabelle(BoxLayout):
pass
Builder.load_string('''
<Tabelle>:
orientation: 'horizontal'
spalte1_SP: 'spalte1'
spalte2_SP: 'spalte2'
spalte3_SP: 'spalte3'
Label:
id: SP1
text: root.spalte1_SP
Label:
id: SP2
text: root.spalte2_SP
Label:
id: SP3
text: root.spalte3_SP
<RV>:
viewclass: 'Tabelle'
RecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'spalte1_SP': str(x['SP1']), 'spalte2_SP': str(x['SP2']), 'spalte3_SP': str(x['SP3'])} for x in items]
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
Upvotes: 5