如何将多个列放入 kivy RecycleView?
How to put multiple columns into a kivy RecycleView?
我想把一个(csv-)table的数据放到一个kivy recycleview中。
如果我将固定文本分配给 kv 中的标签,我设法用一行插入多列,但我无法用字典列表中的数据填充标签。这是到目前为止的代码,我用来测试这个概念:
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()
我希望在 3 列中看到来自 items 的数据,但由于某些原因它们仍然是空的。
它是空的,因为 data
没有填充。
解决方案
- 删除
class Tabelle()
中的所有编码
- 将
pass
添加到 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]
Kivy RecycleView » data
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.
例子
main.py
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()
输出
在前面的解决方案的基础上,这里有一个代码,它的解释要容易得多。此外,其中一列是一个复选框。
结果:
Python 文件:
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文件:
<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'
下面的版本添加了行选择以及名称列的更大标签宽度以及每次选择一行时在 gui class 中调用的方法。:
结果:
Python 文件:
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文件:
<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'
我想把一个(csv-)table的数据放到一个kivy recycleview中。
如果我将固定文本分配给 kv 中的标签,我设法用一行插入多列,但我无法用字典列表中的数据填充标签。这是到目前为止的代码,我用来测试这个概念:
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()
我希望在 3 列中看到来自 items 的数据,但由于某些原因它们仍然是空的。
它是空的,因为 data
没有填充。
解决方案
- 删除
class Tabelle()
中的所有编码
- 将
pass
添加到class Tabelle()
- 将以下内容添加到构造函数中,
__init__()
ofclass RV()
片段
self.data = [{'spalte1_SP': str(x['SP1']), 'spalte2_SP': str(x['SP2']), 'spalte3_SP': str(x['SP3'])} for x in items]
Kivy RecycleView » data
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.
例子
main.py
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()
输出
在前面的解决方案的基础上,这里有一个代码,它的解释要容易得多。此外,其中一列是一个复选框。
结果:
Python 文件:
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文件:
<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'
下面的版本添加了行选择以及名称列的更大标签宽度以及每次选择一行时在 gui class 中调用的方法。:
结果:
Python 文件:
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文件:
<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'