KivyMD update: MDDropdownMenu.open() generates an error - kivy

After updating an old project after a couple of years, I got an error:
TypeError: MDDropdownMenu.open() takes 1 positional argument but 2 were given
The relevant code (it used to work, two years ago), main.py:
def build(self):
...
return Builder.load_file("main.kv")
def on_start(self):
...
self.menu_lang_append()
...
...
def menu_lang_append(self):
self.menu_lang = MDDropdownMenu(width_mult=2)
for lng in co_lang.LANG:
self.menu_lang.items.append(
{
"viewclass": "MDMenuItem",
"text": lng,
"callback": self.menu_lang_callback,
}
)
main.kv:
MDBottomAppBar:
MDToolbar:
id: ps_toolbar
title: T["co-toolbar-title"]
icon: ACTION_ICON
type: "bottom"
animate_action_button: False
next_icon: app.pulse_icon_counter() # Not a callback.
on_action_button: app.discovery_request()
right_action_items: [ ['minus-box-outline', lambda x: app.discovery_clean()], ['earth-box', lambda x: app.menu_lang.open(x)], ['dots-vertical', lambda x: app.menu_main.open(x)], ]
A very similar case here, unresolved.
I tried to add the caller like this, no luck and no wonder; runtime errors
main.py:
self.menu_lang = MDDropdownMenu(width_mult=2, caller=self.root.ids.ps_toolbar)
or
self.menu_lang = MDDropdownMenu(width_mult=2, caller=self.root.ids.ps_toolbar.right_action_items)
main.kv:
right_action_items: [... , ['earth-box', lambda x: app.menu_lang.open()], ...]
Software:
[tool.poetry.dependencies]
python = "^3.10"
Kivy = "^2.1.0"
kivymd = "^0.104.2"

According to #1203, copy/paste/run example:
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from kivy.metrics import dp
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
KV = """
BoxLayout:
MDBottomAppBar:
MDToolbar:
id: toolbar
title: "co-toolbar-title"
icon: "eye"
type: "bottom"
animate_action_button: False
right_action_items: [['earth-box', lambda x: app.menu_lang_open(x)]]
"""
class Contero(MDApp):
menu_lang = ObjectProperty()
def menu_lang_open(self, button):
self.menu_lang.caller = button
self.menu_lang.open()
def menu_item_lang_callback(self, lng):
self.menu_lang.dismiss()
# Handle lng.
def menu_lang_append(self):
items = []
for lng in ["EN", "RU"]:
items.append(
{
"viewclass": "OneLineListItem",
"text": lng,
"height": dp(48),
"on_release": lambda x=lng: self.menu_item_lang_callback(x),
}
)
self.menu_lang = MDDropdownMenu(
width_mult=2,
items=items,
caller=self.root.ids.toolbar.ids.right_actions.children[0],
)
def build(self):
return Builder.load_string(KV)
def on_start(self):
def on_start(interval):
self.menu_lang_append()
Clock.schedule_once(on_start)
Contero().run()

Related

.kv is loaded multiples times, you might have unwanted behaviors

I can run my code but I'm having such unwanted behavior enter image description here, I combined my source code with the https://dev.to/ngonidzashe/how-to-create-a-simple-to-do-list-application-with-kivymd-d89 , and I guess I didn't combine it right here are my code:
import mysql.connector
from kivy.lang import Builder
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.picker import MDDatePicker
from datetime import datetime
from kivymd.uix.list import TwoLineAvatarIconListItem, ILeftBodyTouch
from kivymd.uix.selectioncontrol import MDCheckbox
from database import Database
from kivy.core.window import Window
Window.size = (350, 600)
db = Database()
class MainApp(MDApp):
def build(self):
global screen_manager
screen_manager = ScreenManager()
screen_manager.add_widget(Builder.load_file("login.kv"))
screen_manager.add_widget(Builder.load_file("register.kv"))
screen_manager.add_widget(Builder.load_file("main.kv"))
return screen_manager
database = mysql.connector.connect(host='localhost',
database='loginform',
user='root',
password='****')
cursor = database.cursor()
def send_data(self, user, password):
self.cursor.execute(f"insert into example2 values('{user.text}','{password.text}')")
self.database.commit()
def receive_data(self, user, password):
self.cursor.execute("select * from example2")
user_list = []
for i in self.cursor.fetchall():
user_list.append(i[0])
if user.text in user_list and user.text != "":
self.cursor.execute(f"select password from example2 where user='{user.text}'")
for j in self.cursor:
if password.text == j[0]:
open_button = MDFlatButton(text='Open the App', on_release=self.open_app)
close_button = MDFlatButton(text='Close', on_release=self.close_dialg)
self.dialog = MDDialog(text='Welcome to the *****',
buttons=[close_button, open_button])
self.dialog.open()
else:
try_button = MDFlatButton(text='Try Again', on_release=self.close_dialg)
self.dialog = MDDialog(title='Incorrect Password',
text='You entered wrong password please try again',
buttons=[try_button])
self.dialog.open()
else:
open_regist = MDFlatButton(text="Register", on_release=self.open_regist)
close_button = MDFlatButton(text='Close', on_release=self.close_dialg)
self.dialog = MDDialog(title='Incorrect User',
text='There are no such user',
buttons=[close_button, open_regist])
self.dialog.open()
def open_regist(self, *args):
screen_manager.current = "register"
self.dialog.dismiss()
def close_dialg(self, *args):
self.dialog.dismiss()
def open_app(self, *args):
screen_manager.current = "tasks"
self.dialog.dismiss()
task_list_dialog = None # Here
# Add the below functions
def show_task_dialog(self):
if not self.task_list_dialog:
self.task_list_dialog = MDDialog(
title="Create Task",
type="custom",
content_cls=DialogContent(),
)
self.task_list_dialog.open()
def on_start(self):
"""Load the saved tasks and add them to the MDList widget when the application starts"""
try:
completed_tasks, uncomplete_tasks = db.get_tasks()
if uncomplete_tasks != []:
for task in uncomplete_tasks:
add_task = ListItemWithCheckbox(pk=task[0], text=task[1], secondary_text=task[2])
self.root.ids.container.add_widget(add_task)
if completed_tasks != []:
for task in completed_tasks:
add_task = ListItemWithCheckbox(pk=task[0], text='[s]' + task[1] + '[/s]',
secondary_text=task[2])
add_task.ids.check.active = True
self.root.ids.container.add_widget(add_task)
except Exception as e:
print(e)
pass
def close_dialog(self, *args):
self.task_list_dialog.dismiss()
def add_task(self, task, task_date):
"""Add task to the list of tasks"""
# Add task to the db
created_task = db.create_task(task.text, task_date) # Here
# return the created task details and create a list item
self.root.ids['container'].add_widget(
ListItemWithCheckbox(pk=created_task[0], text='[b]' + created_task[1] + '[/b]',
secondary_text=created_task[2])) # Here
task.text = ''
class DialogContent(MDBoxLayout):
"""OPENS A DIALOG BOX THAT GETS THE TASK FROM THE USER"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
# set the date_text label to today's date when user first opens dialog box
self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y'))
def show_date_picker(self):
"""Opens the date picker"""
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save)
date_dialog.open()
def on_save(self, instance, value, date_range):
"""This functions gets the date from the date picker and converts its it a
more friendly form then changes the date label on the dialog to that"""
date = value.strftime('%A %d %B %Y')
self.ids.date_text.text = str(date)
# create the following two classes
class ListItemWithCheckbox(TwoLineAvatarIconListItem):
"""Custom list item"""
def __init__(self, pk=None, **kwargs):
super().__init__(**kwargs)
# state a pk which we shall use link the list items with the database primary keys
self.pk = pk
def mark(self, check, the_list_item):
"""mark the task as complete or incomplete"""
if check.active == True:
# add strikethrough to the text if the checkbox is active
the_list_item.text = '[s]' + the_list_item.text + '[/s]'
db.mark_task_as_complete(the_list_item.pk) # here
else:
the_list_item.text = str(db.mark_task_as_incomplete(the_list_item.pk)) # Here
def delete_item(self, the_list_item):
"""Delete the task"""
self.parent.remove_widget(the_list_item)
db.delete_task(the_list_item.pk) # Here
class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
"""Custom left container"""
if __name__ == '__main__':
app = MainApp()
app.run()
and here is my kv file with this:
MDScreen:
name: "tasks"
MDFloatLayout:
MDLabel:
id: task_label
halign: 'center'
markup: True
text: "[u][size=48][b]TASKS[/b][/size][/u]"
pos_hint: {'y': .45}
ScrollView:
pos_hint: {'center_y': .5, 'center_x': .5}
size_hint: .9, .8
MDList:
id: container
MDFloatingActionButton:
icon: 'plus-thick'
on_release: app.show_task_dialog() #functionality to be added later
elevation_normal: 12
pos_hint: {'x': .8, 'y':.05}
<DialogContent>:
orientation: "vertical"
spacing: "10dp"
size_hint: 1, None
height: "130dp"
GridLayout:
rows: 1
MDTextField:
id: task_text
hint_text: "Add Task..."
pos_hint: {"center_y": .4}
max_text_length: 50
on_text_validate: (app.add_task(task_text, date_text.text), app.close_dialog())
MDIconButton:
icon: 'calendar'
on_release: root.show_date_picker()
padding: '10dp'
MDLabel:
spacing: '10dp'
id: date_text
BoxLayout:
orientation: 'horizontal'
MDRaisedButton:
text: "SAVE"
on_release: (app.add_task(task_text, date_text.text), app.close_dialog())
MDFlatButton:
text: 'CANCEL'
on_release: app.close_dialog()
<ListItemWithCheckbox>:
id: the_list_item
markup: True
LeftCheckbox:
id: check
on_release:
root.mark(check, the_list_item)
IconRightWidget:
icon: 'trash-can-outline'
theme_text_color: "Custom"
text_color: 1, 0, 0, 1
on_release:
root.delete_item(the_list_item)
I would be very thankful if someone can help or give some tips, how to improve. I'm open to have private conversation.
A kv file with the name main.kv will be loaded automatically by Kivy for your application (See documentation). So your code:
screen_manager.add_widget(Builder.load_file("main.kv"))
is loading main.kv a second time. The easiest fix is to just rename the main.kv file.

Python3 KivyMD - MDDialog get ItemConfirm text value

I want to pass to my project_selected function the selected item in my MDDialog after pressing the OK button. But I can't figure out how can I get the value and do this.
I could print the value inside my set_icon funtion in ItemConfirm class, but I don't know whats the better way to pass that value to HomeWindow(Screen) class or if it is possible to call it directly from inside of it once that the ItemConfirm is already called from inside a function that is part of HomeWindow class.
main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.app import MDApp
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import OneLineAvatarIconListItem
class ItemConfirm(OneLineAvatarIconListItem):
divider = None
def set_icon(self, instance_check):
print(self.text)
instance_check.active = True
check_list = instance_check.get_widgets(instance_check.group)
for check in check_list:
if check != instance_check:
check.active = False
class HomeWindow(Screen):
dialog = None
def show_confirmation_dialog(self):
projects = [{id: 0, name: "example1"},{id: 1, name: "example2"}]
if not self.dialog:
self.dialog = MDDialog(
title="Projects",
type="confirmation",
auto_dismiss=False,
items=[ItemConfirm(text=f"{project['name']}") for project in projects],
buttons=[
MDFlatButton(text="CANCEL", theme_text_color="Custom"),
MDFlatButton(
text="OK",
theme_text_color="Custom",
on_release=self.project_selected,
),
],
)
self.dialog.open()
def project_selected(self, *args, **kwargs):
self.ids.project_selection.text = self.dialog.text
class WindowManager(ScreenManager):
pass
class RlogTimer(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
self.root = Builder.load_file("templates/main.kv")
return self.root
if __name__ == "__main__":
RlogTimer().run()
templates/main.kv
#: import NoTransition kivy.uix.screenmanager.NoTransition
WindowManager:
HomeWindow:
<ScreenManager>:
transition: NoTransition()
<ItemConfirm>:
on_release: root.set_icon(check)
CheckboxLeftWidget:
id: check
group: "check"
<HomeWindow>:
name: "home"
MDBoxLayout:
orientation: "vertical"
MDToolbar:
id: title
title: "Redmine logTimer"
right_action_items: [["clock", lambda x: app.callback_2()]]
MDFlatButton:
id: project_selection
text: "Select Project"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: root.show_confirmation_dialog()
You can achieve that as follows,
First create a prop. say, selected_project in HomeWindow as,
class HomeWindow(Screen):
dialog = None
selected_project = StringProperty()
Now set its value in method set_icon as,
def set_icon(self, instance_check):
...
app = MDApp.get_running_app() # Access the running app instance.
home_screen = app.root.get_screen("home") # Access required screen.
home_screen.selected_project = self.text # Now set value.
...
Now it's time to set this value in method project_selected,
def project_selected(self, *args, **kwargs):
self.ids.project_selection.text = self.selected_project

Add KivyMD Expansion Panel inside RecyleView kivy

anyone can help me about how to add KivyMD Expansion Panel in RecycleView kivy? Because I have issue with slow perfomance while add MDExpansionPanel with "add_widget" on kivy (run in old android).
Then i have idea to put Expansion into RecycleView, but the expansionpanel can't open with true index.
fyi, i have make custom expansion.py file
expansion.py
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.button import MDIconButton
from kivymd.uix.list import (IRightBody, ILeftBody, TwoLineAvatarIconListItem)
from kivymd.uix.selectioncontrol import MDCheckbox
Builder.load_string(
"""
#:import images_path kivymd.images_path
#:import md_icons kivymd.icon_definitions.md_icons
<CustomExpansionPanel>
text: root.title
secondary_text: root.desc
_no_ripple_effect: True
IconRightSampleWidget:
id: check
disabled_color: [.2, .3, .6, .9]
disabled: True
ChevronRight:
id: chevron
icon: 'chevron-right'
disabled: True
canvas.before:
PushMatrix
Rotate:
angle: self.angle
axis: (0, 0, 1)
origin: self.center
canvas.after:
PopMatrix
<CustomMDExpansionPanel>
size_hint_y: None
height: dp(68)
padding:dp(0)
BoxLayout:
id: box_item
size_hint_y: None
height: root.height
orientation: 'vertical'
CustomExpansionPanel:
id: item_anim
title: root.title
desc: root.desc
on_press: root.check_open_box(self)
"""
)
class IconRightSampleWidget(ILeftBody, MDCheckbox):
pass
class ChevronRight(IRightBody, MDIconButton):
angle = NumericProperty(0)
class CustomExpansionPanel(TwoLineAvatarIconListItem):
title = StringProperty()
desc = StringProperty()
class CustomMDExpansionPanel(BoxLayout):
content = ObjectProperty()
title = StringProperty()
desc = StringProperty()
def __init__(self, **kwargs):
super(CustomMDExpansionPanel, self).__init__(**kwargs)
self.register_event_type("on_open")
self.register_event_type("on_close")
def on_open(self, *args):
pass
def on_close(self, *args):
pass
def check_open_box(self, instance,CloseAll=False):
press_current_item = False
for box in self.parent.children:
if isinstance(box, CustomMDExpansionPanel):
if len(box.ids.box_item.children) == 2:
if instance is box.ids.item_anim:
press_current_item = True
box.ids.box_item.remove_widget(box.ids.box_item.children[0])
chevron = box.ids.box_item.children[0].ids.chevron
self.anim_chevron_up(chevron)
self.anim_resize_close(box)
self.dispatch("on_close")
break
if not press_current_item and not CloseAll:
self.anim_chevron_down()
def anim_chevron_down(self):
chevron = self.ids.item_anim.ids.chevron
angle = -90
Animation(angle=angle, d=0.2).start(chevron)
self.anim_resize_open_item()
self.dispatch("on_open")
def anim_chevron_up(self, instance):
angle = 0
Animation(angle=angle, d=0.2).start(instance)
def anim_resize_close(self, box):
Animation(height=dp(68), d=0.1, t="in_cubic").start(box)
def anim_resize_open_item(self, *args):
self.content.name_item = self.title
anim = Animation(
height=self.content.height + dp(70), d=0.2, t="in_cubic"
)
anim.bind(on_complete=self.add_content)
anim.start(self)
def add_content(self, *args):
if self.content and len(self.ids.box_item.children) == 1:
self.ids.box_item.add_widget(self.content)
main.py
from kivymd.app import MDApp as App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from expansion import CustomMDExpansionPanel
from time import time
from kivy.uix.boxlayout import BoxLayout
Builder.load_string(
"""
<ListScreen>:
recycle_view: recycle_view
RecycleView:
id: recycle_view
size_hint: 1, 0.9
viewclass: "CustomMDExpansionPanel"
RecycleGridLayout:
id: items_box
cols:1
default_size_hint: 1, None
size_hint: 1, None
height:self.minimum_height
"""
)
class Container(BoxLayout):
def __init__(self,**kwargs):
super(Container,self).__init__()
class ListScreen(Screen):
recycle_view = ObjectProperty(None)
items_box = ObjectProperty(None)
def on_enter(self):
start = time()
container = []
for i in range(0,50):
container.append(Container(item='strrr'+str(i), index=i))
self.recycle_view.data.append(
{
'content':container[i],
'title':'title'+str(i),
'desc':'desc'+str(i)
}
)
def on_leave(self):
self.recycle_view.data = []
class ListApp(App):
sm = ScreenManager()
screens = {}
def build(self):
self.__create_screens()
ListApp.sm.add_widget(ListApp.screens['list1'])
return ListApp.sm
def __create_screens(self):
ListApp.screens['list1'] = ListScreen(name='list1')
if __name__ == '__main__':
ListApp().run()
Thank You
From my understanding , if you are trying to add your expansion panel inside the RecycleView.
Here is an example code of how to do that
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelThreeLine
from kivymd import images_path
KV = """
<Content>
adaptive_height: True
TwoLineIconListItem:
text: "(050)-123-45-67"
secondary_text: "Mobile"
RecycleView:
MDGridLayout:
id: box
cols: 1
adaptive_height: True
"""
class Content(MDBoxLayout):
"""Custom content."""
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(10):
self.root.ids.box.add_widget(
MDExpansionPanel(
icon=f"{images_path}kivymd.png",
content=Content(),
panel_cls=MDExpansionPanelThreeLine(
text="Text",
secondary_text="Secondary text",
tertiary_text="Tertiary text",
),
)
)
Test().run()
Please Refer Documentations Before Asking Questions :) As It Solves 90 % Of Your Problems <3
Also Edit Your Question And Specify Your Problem Clearly :)

Recycleview AttributeError: 'super' object has no attribute '__getattr__'

please check why the below program is giving an
AttributeError: 'super' object has no attribute '__getattr__'
.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, ObjectProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
# from kivy.effects.scroll.ScrollEffect import ScrollEffect
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.recycleboxlayout import RecycleBoxLayout
Builder.load_file('so_extractTIC.kv')
class RecycleItem(ScreenManager,RecycleDataViewBehavior, TextInput):
index = NumericProperty(0)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class DataView(Screen):
DataList = ListProperty()
TextInputNum = NumericProperty(10)
def __init__(self,*args,**kwargs):
super(DataView, self).__init__(*args,**kwargs)
# for key, val in self.ids.items():
# print("key={0}, val={1}".format(key, val))
data12= []
for x in range(self.TextInputNum):
data12.append({'text': '', 'height': 50})
self.ids.rv.data = data12
def extract_data(self,rv):
print(self.parent.parent.parent)
self.DataList.clear()
for x in range(self.TextInputNum):
self.DataList.append(self.ids.rv.data[x]['text'])
print(self.DataList)
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
# self.root = Builder.load_string(APP_KV)
return RootWidget()
if __name__ == '__main__':
MainApp().run()
.kv:
<DataView>:
BoxLayout:
orientation: 'vertical'
RecycleView:
size_hint_y: 0.9
viewclass: 'RecycleItem'
id: rv
key_size: 'size'
# effect_cls: ScrollEffect
cols: 1
RecycleBoxLayout:
id: rvbox
cols: rv.cols
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data()
<RecycleItem>:
on_text: self.parent.parent.data[self.index]['text'] = self.text
<RootWidget>:
DataView:
name:"DataView_screen"
I have been searching for extract data from recycleview using textInput boxes. Please find the link for the query:
Retrieve Data from Kivy Recycleview
I am trying to inherit from ScreenManager, but it is giving the 'super' attribute error. Tried passing id as argument in the .kv and tried to find real parent but nothing works.
Also, please suggest how to use the above code for recycle GridLaout, with 2d rows and columns, i tried using for loops, but getting key related errors.
like:
for z in range(12):
for y in range(8):
self.table_data12.append(self.ids.idname.data[y][z]['text'])
thanks!
In your DataView class, the __init__() method references self.ids, but the ids are not yet available at that point. You can delay that referencing by using Clock.schedule_once() like this:
def __init__(self, *args, **kwargs):
super(DataView, self).__init__(*args, **kwargs)
# for key, val in self.ids.items():
# print("key={0}, val={1}".format(key, val))
Clock.schedule_once(self.setup_data)
def setup_data(self, dt):
data12 = []
for x in range(self.TextInputNum):
data12.append({'text': '', 'height': 50})
self.ids.rv.data = data12
I see no reason for making the RecycleItem a subclass of ScreenManager.
In your 'kv, the on_textline forRecycleItem` can be:
<RecycleItem>:
on_text: app.root.get_screen('DataView_screen').ids.rv.data[self.index]['text'] = self.text
And the submit Button can be:
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data(rv)

Retrieve Data from Kivy Recycleview

I am able to make a recycle view layout of TextInput boxes. Now, further, I would like to give text input in these boxes and gather these inputs in the form of list or dict.
I have tried, self.ids.idname.data to append in an empty list but it didn't work.
Following an example showing how to extract TextInput entries under a RecycleView and put that into a list:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, ObjectProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
APP_KV = """
#:import ScrollEffect kivy.effects.scroll.ScrollEffect
<DataView>:
orientation: 'vertical'
RecycleView:
id: rv
size_hint_y: 0.9
viewclass: 'RecycleItem'
key_size: 'size'
effect_cls: ScrollEffect
cols: 1
RecycleBoxLayout:
id: rvbox
cols: rv.cols
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data()
<RecycleItem>:
on_text: self.parent.parent.data[self.index]['text'] = self.text
"""
class RecycleItem(RecycleDataViewBehavior, TextInput):
index = NumericProperty(0)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class DataView(BoxLayout):
DataList = ListProperty()
TextInputNum = NumericProperty(10)
def __init__(self, **kwargs):
super().__init__(**kwargs)
data = []
for x in range(self.TextInputNum):
data.append({'text': '', 'height': 50})
self.ids.rv.data = data
def extract_data(self):
self.DataList.clear()
for x in range(self.TextInputNum):
self.DataList.append(self.ids.rv.data[x]['text'])
print(self.DataList)
class MainApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return DataView()
if __name__ == '__main__':
MainApp().run()

Resources