I am studying kivy for now and reading Creating Apps with kivy. Author use follwing code:
.kv
AddLocationForm:
<AddLocationForm#BoxLayout>:
orientation : 'vertical'
BoxLayout:
pos : 100, 100
height : '40dp'
size_hint_y : None
TextInput:
size_hint_x : 50
Button:
text : 'search'
size_hint_x : 25
Button:
text : 'current location'
size_hint_x : 25
ListView:
item_strings: ["Palo Alto, MX", "Palo Alto, US"]
and .py
from kivy.app import App
class FirstKivyApp(App):
pass
FApp = FirstKivyApp()
FApp.run()
But as much as I understand ListView is deprecated now. It is supposed to be changed on RecycleView now. I've checked for some solutions but they don't make sense for me because use things I've not accomplished yet. I tried to use
RecycleView:
data : ["Palo Alto, MX", "Palo Alto, US"]
instead of ListView but it isn't shown whereas I can access the data through id and ObjectProperty. Is there a way to display data in simplier way, than using ScreenManager, constructing classes and referring to build method? For example something like in author's or my example, but working. Adding RecycleBoxLayout didn't work too.
When calling your Recycleview in kivy, make sure it has an appropriate id, this can then be called in your python code with data applied with the following:
rows = ["Palo Alto, MX", "Palo Alto, US"] # declare list
self.ids.rv.data = [{'text':str(row)}for row in rows] # add list
The kivy docs site has a great example of how to implement RecycleView, found here: https://kivy.org/doc/stable/api-kivy.uix.recycleview.html
Try this for a basic example showing how to use ScreenManager with RecycleView:
import kivy
# import main libraries, import object types and layouts
from kivy.config import Config
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.properties import (StringProperty, ObjectProperty,
OptionProperty, NumericProperty, ListProperty, BooleanProperty)
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.behaviors import FocusBehavior
# import screen features
from kivy.uix.label import Label
from kivy.uix.button import Button
# load in kv file, deals with cosmetics of each screen
kv = """
<SelectableLabel>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if root.selected else (0, 0, 0, .1)
Rectangle:
pos: self.pos
size: self.size
<SelectScreen>:
BoxLayout:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
orientation: 'vertical'
GridLayout:
cols: 2
rows: 1
size_hint_y: .25
height: dp(54)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Select all'
font_size: 24
on_release:
controller.select_all(len(rv.data))
Button:
text: 'Deselect all'
font_size: 24
on_release:
controller.clear_all()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
id: controller
key_selection: 'selectable'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
spacing: dp(2)
"""
Builder.load_string(kv)
# Adds selectable labels to lists (recycleview)
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
def get_nodes(self):
nodes = self.get_selectable_nodes()
if self.nodes_order_reversed:
nodes = nodes[::-1]
if not nodes:
return None, None
selected = self.selected_nodes
if not selected: # nothing selected, select the first
self.select_node(nodes[0])
return None, None
if len(nodes) == 1: # the only selectable node is selected already
return None, None
last = nodes.index(selected[-1])
self.clear_selection()
return last, nodes
def select_all(self, num):
print(num)
#print(len(self.ids.rv.data))
last, nodes = self.get_nodes()
print(nodes)
for x in range(num):
print(x)
self.select_node(x)
def clear_all(self):
self.clear_selection()
# Create action on selectable list, for example apply selection remembers previous selection and saves to sqlite db
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
index = int
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, 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):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if self.selected:
print("selection changed to {0}".format(rv.data[index]))
else:
print("selection removed for {0}".format(rv.data[index]))
# Screen for selecting from recycleview
class SelectScreen(Screen):
interfacename = StringProperty()
def __init__(self, **kwargs):
super(SelectScreen, self).__init__(**kwargs)
rows = ["Palo Alto, MX", "Palo Alto, US"] # declare list
self.ids.rv.data = [{'text':str(row)}for row in rows] # add list
def select(self): # selects participants from list new value to database
print (self.ids.rv.data[val[0]]['text'])
def selectall(self):
for num in range(len(self.ids.rv.data)):
SelectableLabel.apply_selection(self, self.ids.rv, num, True)
# screen manager
sm = ScreenManager()
sm.add_widget(SelectScreen(name='select')) # main starting menu
# Build the app return screenmanager
class RecycleviewApp(App):
def build(self):
return sm
if __name__ == '__main__':
RecycleviewApp().run()
Example image of application and terminal printing application and removal of RecycleView selection:
I founded out the issue.
Firstly, format of data must be suitable. As twicejiggled showed it must be list of dicts.
Secondly, as much as I understood, some layout is neede for showing. For example this code in .kv will work:
RecycleView:
data : [{'text':'text'} for x in range(50)]
viewclass: 'Label'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Related
I want to user to see the spinner when they reach the bottom of the Recycleview..
In this bellow code the spinner is visible in the viewport this is the issue so there is some code below..
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import Screen
Builder.load_string('''
<MyScreen>:
ScrollView:
BoxLayout:
orientation:"vertical"
size_hint_y:None
height:root.height
RV:
size_hint_y:None
height:root.height
viewclass: 'Button'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
size_hint_y:None
height:self.minimum_height
MDSpinner:
size_hint:None,None
width:dp(40)
height:dp(20)
pos_hint:{"center_x":.5}
''')
class MyScreen(Screen):
pass
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(25)]
class TestApp(MDApp):
def build(self):
return MyScreen()
if __name__ == '__main__':
TestApp().run()
Thanks in advance..
If you want the last item in the RecycleView to be a spinner, you cannot do that with a viewclass of Button (unless you can make a Button look like a Spinner). However, you can design your own viewclass that can look like either a Button or a Spinner. So defining a custom viewclass like this:
class MyViewClass(RelativeLayout):
text = StringProperty('') # text for the Button
spinner = BooleanProperty(False) # if True, show a Spinner instead
Then add a rule for it in your kv:
<MyViewClass>:
Button:
text: root.text
opacity: 0 if root.spinner else 1
MDSpinner:
pos_hint:{"center_x":.5}
opacity: 1 if root.spinner else 0
active: True if root.spinner else False
size_hint: None, None
height: root.height
width: root.height
The above rule uses opacity to determine whether the Button or the Spinner is visible. And the active attribute of the MDSpinner is used to avoid having a spinning MDSpinner running in the items where it is not visible.
Then just specify MyViewClass as the viewclass:
viewclass: 'MyViewClass'
And remove the old MDSpinner from your kv.
The last thing to do is to adjust your data:
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x), 'spinner': False} for x in range(25)]
self.data.append({'text': '', 'spinner': True})
The data now sets spinner to False for all the entries, and adds an extra entry with spinner set to True.
I am using Kivy and KivyMD and running into an issue when combining a Kivy RecycleView with a KivyMD HoverBehavior. What happens is that the bottom element in my list (inside the recycle view) behaves the way I expect it to with the hover behavior, correctly detecting when the mouse enters and exits the bounding box of the list element. However, as I move up higher on the list, the element that is being detected as hovered gets further and further from where my mouse pointer actually is.
For example, when hovering over element 10 of 10, the on_enter and on_leave methods of the hover behavior correctly show that, but I would have to hover over element 8 to get element 9 to be detected, 6 to get 8 to be detected, and so on.
Here is the code I have so far, pared down as far as I can to be able to reproduce the issue. You can install the dependencies (Kivy and KivyMD) and run the code. From there, just try to hover over various elements in the list and notice how the wrong checkboxes appear checked and the wrong element numbers output to the console.
What might be causing this type of behavior?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty, StringProperty
from kivymd.uix.behaviors import HoverBehavior
from kivy.uix.relativelayout import RelativeLayout
Builder.load_string('''
<RV>:
viewclass: 'TestItem'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
<TestItem>:
canvas:
Color:
rgba: .8, .8, .8, 1
Line:
points: 0,0,self.width,0
width:1
CheckBox:
id: "checkbox"
active: True if root.status == 'completed' else False
Label:
size_hint_x: .86
text: root.title
''')
class TestItem(RecycleDataViewBehavior, RelativeLayout, HoverBehavior):
''' Add selection support to the Label '''
status = StringProperty()
title = StringProperty()
def on_enter(self, *args):
self.children[1].background_checkbox_normal ="atlas://data/images/defaulttheme/checkbox_on"
print("Entering", self.title)
def on_leave(self, *args):
self.children[1].background_checkbox_normal ="atlas://data/images/defaulttheme/checkbox_off"
print("Leaving", self.title)
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'title': str(x), 'status': "not started"} for x in range(10)]
self.refresh_from_data()
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
The HoverBehavior does not appear to work correctly for RelayiveLayout. Try changing
class TestItem(RecycleDataViewBehavior, RelativeLayout, HoverBehavior):
to
class TestItem(RecycleDataViewBehavior, HoverBehavior, FloatLayout):
That will also require refactoring the <TestItem> rule in your kv. Something like:
<TestItem>:
canvas:
Color:
rgba: .8, .8, .8, 1
Line:
points: self.x, self.y,self.width,self.y
width:1
CheckBox:
id: "checkbox"
size_hint_x: .14
pos_hint: {'x': 0.86}
center_y: root.center_y
active: True if root.status == 'completed' else False
Label:
size_hint_x: .86
pos_hint: {'x': 0}
center_y: root.center_y
text: root.title
So, I'm trying to create a list that pulls from a mysql database that displays an order # as a button and a new window expands to display the order numbers items/subitems with checkboxes to have checked when an item is selected. I have the window to pop up; however, nothing populates and my query prints out information/list. After all boxes are checked and a Finish button is clicked on, it will remove the order from the list to show it has been worked on. I found this on the forums; however, it's not pulling anything for me:
How to fetch data from database and show in table in kivy+python
Thank you!
main.py
import pymysql
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
orderNum = "1"
class TextInputPopup(Popup):
obj = ObjectProperty(None)
obj_text = StringProperty("")
def __init__(self, obj, **kwargs):
super(TextInputPopup, self).__init__(**kwargs)
self.obj = obj
self.obj_text = obj.text
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
def on_press(self):
popup = TextInputPopup(self)
popup.open()
def update_changes(self, txt):
self.text = txt
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_order()
def get_order(self):
connection = pymysql.connect(host='localhost', user='root',passwd='password', db='Shop')
cursor = connection.cursor()
cursor.execute("SELECT itemName, ITEM FROM order_list WHERE orderID=%s", (orderNum,))
rows = cursor.fetchall()
# create data_items
for row in rows:
for col in row:
self.data_items.append(col)
class TestApp(App):
title = "Kivy RecycleView & pymysql Demo"
def build(self):
return RV()
if __name__ == "__main__":
TestApp().run()
kivy.kv
#:kivy 1.10.0
<TextInputPopup>:
title: "Popup"
size_hint: None, None
size: 400, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
TextInput:
id: txtinput
text: root.obj_text
Button:
size_hint: 1, 0.2
text: "Finish"
on_release:
root.obj.update_changes(txtinput.text)
root.dismiss()
Button:
size_hint: 1, 0.2
text: "Cancel Changes"
on_release: root.dismiss()
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 2
Label:
text: "Order Number"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.data_items]
SelectableRecycleGridLayout:
cols: 2
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
Here's my list that pulls information and uses a print function:
('Sub', 'Italian')
('Sub', 'Meatball')
('Drink', 'Apple Juice')
('Side', 'Salad')
('Soup', 'Chicken and rice')
What I have and What I'm Trying to Achieve
So I learning Kivy but I am stuck with the ListView or, as the ListView seems to be deprecated, the RecycleView.
My problem is that I want the label with species_text as ID to change based on the item I click on, once in the label is in view.
The documentation helped me as far as making the SelectableLabel and being able to click / color it, but I do not know how to change the text of species_text via the data list of the RecycleView or how to save the data list in the ScreenTest class.
Here is my code:
from kivy.app import App
from kivy.uix.button import Label, Button
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<ScreenTest>:
Label:
pos_hint: {"x": .45, "top": 1}
text: "Headline"
size_hint: .1, .1
BoxLayout:
pos_hint: {"x": 0.02, "top": .8}
RecycleView:
id: species_list_view
data: [{'name': "Species1", "text": "S1"}, {'name': "Species2", "text": "S2"}]
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
orientation: 'vertical'
multiselect: False
touch_multiselect: False
Label:
id: species_text
text: "Speciestext"
BoxLayout:
size_hint_y: None
height: 30
spacing: 10
canvas:
Color:
rgba: .5, .2, .1, 1
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Go Back"
Button:
text: "Next"
<SelectableLabel>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
""")
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, 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):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
else:
print("selection removed for {0}".format(rv.data[index]))
class ScreenTest(Screen):
pass
screen_manager = ScreenManager()
screen_manager.add_widget(ScreenTest(name="screen_test"))
class TestApp(App):
def build(self):
return screen_manager
test_app = TestApp()
test_app.run()
Thanks for your help!
The apply_selection() method has RecycleView arguments, taking into account that we can create a property that has the selected text, and then we make a bind with the text of the Label:
...
RecycleView:
id: species_list_view
data: [{'name': "Species1", "text": "S1"}, {'name': "Species2", "text": "S2"}]
viewclass: 'SelectableLabel'
text_selected: "" # create property
SelectableRecycleBoxLayout:
...
Label:
id: species_text
text: "Speciestext" if not species_list_view.text_selected else species_list_view.text_selected # apply binding
...
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
rv.text_selected = rv.data[index]['text'] # set text
else:
print("selection removed for {0}".format(rv.data[index]))
When you select the SelectableLabel you must find the "species_text" Label and change its text.
One way to do that is from its "apply_selection" method.
if is_selected:
for screen in App.get_running_app().root.screens:
if screen.name == "screen_test":
screen.ids.species_text.text = rv.data[index]["name"]
P.S. There is a typo in the kv code:
The "touch_multiselect" attribute is written "touc_multiselect"
I have a question regarding Kivy listview and Pandas dataframes. Specifically how to list data from .xlsx to listview of kivy and then lets say delete selected entry.This is my main code:
import pandas
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.listview import ListItemButton
class ItemsListItemButton(ListItemButton):
pass
class QuestionDb(BoxLayout):
items_list = ObjectProperty()
def dataframe(self):
df = pandas.read_excel("items.xlsx")
return df
class QuestionApp(App):
def build(self):
return QuestionDb()
Questionapp= QuestionApp()
Questionapp.run()
This is question.kv file used to get the listview and button
#: import main question
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import LitsItemButton kivy.uix.listview.ListItemButton
QuestionDb:
<QuestionDb>:
items_list: items_list_view
ListView:
id:items_list_view
adapter:
ListAdapter(data=main.QuestionDb.dataframe(self) ,
cls=main.ItemsListItemButton)
Button:
text: "Deletes selected entry on press"
And this is the excel spreadsheet "items.xlsx" which we set as our dataframe:
Item: Cost: Remaining:
Boots 10$ 5
Socks 2$ 4
Hats 5$ 10
Now with this setup listview in kivy only shows the column names and lists no other items, how can i make it so that items are listed example:
Boots 10$ 5
Socks 2$ 4
Hats 5$ 10
Instead of this
Also any tips on how to link the button to afterwards delete the selected entry would be appreciated as well.
Hope this makes sense.
You should use Recycleview because Listview has been deprecated since version 1.10.0.
In the example below, we are using a Recycleview with selectable recycle grid layout of buttons. Recycleview supports scrolling up and down. We have binded the button with on_release event. You can also change the button to bind on_press event. Click on any row will invoke the method, delete_row.
Kivy RecycleView Documentation
Example
question.py
import pandas
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.core.window import Window
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
class QuestionDb(BoxLayout):
items_list = ObjectProperty(None)
column_headings = ObjectProperty(None)
rv_data = ListProperty([])
def __init__(self, **kwargs):
super(QuestionDb, self).__init__(**kwargs)
self.get_dataframe()
def get_dataframe(self):
df = pandas.read_excel("items.xlsx")
# Extract and create column headings
for heading in df.columns:
self.column_headings.add_widget(Label(text=heading))
# Extract and create rows
data = []
for row in df.itertuples():
for i in range(1, len(row)):
data.append([row[i], row[0]])
self.rv_data = [{'text': str(x[0]), 'Index': str(x[1]), 'selectable': True} for x in data]
def delete_row(self, instance):
# TODO
print("delete_row:")
print("Button: text={0}, index={1}".format(instance.text, instance.index))
print(self.rv_data[instance.index])
print("Pandas: Index={}".format(self.rv_data[instance.index]['Index']))
class QuestionApp(App):
def build(self):
Window.clearcolor = (1, 1, 1, 1) # white background
return QuestionDb()
if __name__ == "__main__":
QuestionApp().run()
question.kv
#:kivy 1.10.0
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (0, 0.517, 0.705, 1) if self.selected else (0, 0.517, 0.705, 1)
Rectangle:
pos: self.pos
size: self.size
background_color: [1, 0, 0, 1] if self.selected else [1, 1, 1, 1] # dark red else dark grey
on_release: app.root.delete_row(self)
<QuestionDb>:
column_headings: column_headings
orientation: "vertical"
Label:
canvas.before:
Color:
rgba: (0, 0, 1, .5) # 50% translucent blue
Rectangle:
pos: self.pos
size: self.size
text: 'Click on any row to delete'
size_hint: 1, 0.1
GridLayout:
canvas.before:
Color:
rgba: (1, 0.2, 0, .5) # 50% translucent orange red
Rectangle:
pos: self.pos
size: self.size
id: column_headings
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
BoxLayout:
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3)
Rectangle:
pos: self.pos
size: self.size
RecycleView:
viewclass: 'SelectableButton'
data: root.rv_data
SelectableRecycleGridLayout:
cols: 3
key_selection: 'selectable'
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
Output