user.py
import kivy
kivy.require('1.9.0') # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
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
from kivy.core.window import Window
Window.size = (500, 500)
#con = lite.connect('fact.db')
#con.text_factory = str
#cur = con.cursor()
class TextInputPopup(Popup):
obj = ObjectProperty(None)
obj_text = StringProperty("")
#print(obj);
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,*args):
popup = TextInputPopup(self)
popup.open()
def update_changes(self):
self.text = txt
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_users()
def get_users(self):
#cur.execute("SELECT * FROM `users` order by id asc")
#rows = cur.fetchall()
'''This result retrieve from database'''
rows = [(1, 'Yash', 'Chopra'),(2, 'amit', 'Kumar')]
for row in rows:
for col in row:
self.data_items.append(col)
class ListUser(App):
title = "Users"
def build(self):
self.root = Builder.load_file('user.kv')
return RV()
if __name__ == '__main__':
ListUser().run()
user.kv
#:kivy 1.10.0
<TextInputPopup>:
title: "Update State"
size_hint: None, None
size: 350, 350
auto_dismiss: False
BoxLayout:
orientation: "vertical"
TextInput:
id: txtinput
text: root.obj_text
Button:
size_hint: 1, 0.4
text: "Save Changes"
on_release:
root.obj.update_changes(txtinput.text)
root.dismiss()
Button:
size_hint: 1, 0.4
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: 3
Label:
text: "ID"
Label:
text: "First Name"
Label:
text: "Last Name"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.data_items]
SelectableRecycleGridLayout:
cols: 3
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
Now my first window showing Like this -First Screen
Now my second window showing Like this - Second Screen
But i want to my second window screen like this -Second Screen
I am new to kivy/python.
I am retrieving data from database and showing in list.Now i am clicking on any column then it shows only self column value like this 2: https://i.stack.imgur.com/Ieiut.jpg.I couldn't pass three variable.
I want to pass row value like third screenshot 3: https://i.stack.imgur.com/UIyV5.jpg.But i don't know how to do?Please anyone can suggest me how do i do this.
Please refer to the explanations, and example for details.
Click A Row - Show All Columns
The view in RecycleView is generatad by processing the data which is essentially a list of dicts. Firstly, we will hook up to the RecycleView's data.
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
self.rv_data = rv.data
Secondly, we will determine the start point of the row when any button in the row is pressed, as follow. We will pass self to the Edit class.
def on_press(self):
self.start_point = 0
end_point = MAX_TABLE_COLS
rows = len(self.rv_data) // MAX_TABLE_COLS
for row in range(rows):
# check index is in column range
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = Edit(self)
popup.open()
Thirdly, in the Edit class (popup widget), we defined the popup's content as a container (BoxLayout). Inside the BoxLayout, there is a GridLayout (containing Labels and TextInput), and two Buttons (Save, and Cancel). We extract the start point and the column data as follow:
class Edit(Popup):
start_point = NumericProperty(0)
col_data = ListProperty(["?", "?", "?"])
def __init__(self, obj, **kwargs):
super(Edit, self).__init__(**kwargs)
self.start_point = obj.start_point
self.col_data[0] = obj.rv_data[obj.start_point]["text"]
self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]
Example
main.py
import kivy
kivy.require('1.10.0') # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.lang import Builder
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
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
from kivy.core.window import Window
Window.size = (500, 500)
MAX_TABLE_COLS = 3
con = lite.connect('company.db')
# con.text_factory = str
cur = con.cursor()
class Edit(Popup):
start_point = NumericProperty(0)
col_data = ListProperty(["?", "?", "?"])
def __init__(self, obj, **kwargs):
super(Edit, self).__init__(**kwargs)
self.start_point = obj.start_point
self.col_data[0] = obj.rv_data[obj.start_point]["text"]
self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]
def package_changes(self, fname, lname):
self.col_data[1] = fname
self.col_data[2] = lname
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)
rv_data = ObjectProperty(None)
start_point = NumericProperty(0)
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
self.rv_data = rv.data
def on_press(self):
self.start_point = 0
end_point = MAX_TABLE_COLS
rows = len(self.rv_data) // MAX_TABLE_COLS
for row in range(rows):
# check index is in column range
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = Edit(self)
popup.open()
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_users()
def get_users(self):
'''This result retrieve from database'''
cur.execute("SELECT * FROM Users ORDER BY UserID ASC")
rows = cur.fetchall()
# create data_items
for row in rows:
for col in row:
self.data_items.append(col)
def update_changes(self, obj):
# update data_items
# obj.start_point + 1 --- skip UserID
for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
self.data_items[index] = obj.col_data[index - obj.start_point]
# update Database Table
cur.execute("UPDATE Users SET FirstName=?, LastName=? WHERE UserID=?", (obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
class ListUser(App):
title = "Users"
def build(self):
self.root = Builder.load_file('test.kv')
return RV()
if __name__ == '__main__':
ListUser().run()
test.kv
#:kivy 1.10.0
<Edit>:
title: "Update State"
size_hint: None, None
size: 350, 350
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: "UserID"
Label:
id: userid
text: root.col_data[0]
Label:
text: "First Name"
TextInput:
id: fname
text: root.col_data[1]
Label:
text: "Last Name"
TextInput:
id: lname
text: root.col_data[2]
Button:
size_hint: 1, 0.4
text: "Save Changes"
on_release:
root.package_changes(fname.text, lname.text)
app.root.update_changes(root) # pass obj
root.dismiss()
Button:
size_hint: 1, 0.4
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: 3
Label:
text: "ID"
Label:
text: "First Name"
Label:
text: "Last Name"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.data_items]
SelectableRecycleGridLayout:
cols: 3
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
Output
Here is a Popup which takes a list as parameter in its open method. You only need to pass that parameter in your code.
py:
class MyPopup(Popup):
text1 = StringProperty()
text2 = StringProperty()
text3 = StringProperty()
def open(self, text, **kwargs):
self.text1 = text[0]
self.text2 = text[1]
self.text3 = text[2]
super(MyPopup, self).open(**kwargs)
kv:
#:import F kivy.factory.Factory
<MyPopup>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Close me!'
on_release: root.dismiss()
TextInput:
text: root.text1
TextInput:
text: root.text2
TextInput:
text: root.text3
This is the whole code for a minimum working example. Do not forget the factory part.
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.properties import StringProperty
class MyPopup(Popup):
text1 = StringProperty()
text2 = StringProperty()
text3 = StringProperty()
def open(self, text, **kwargs):
self.text1 = text[0]
self.text2 = text[1]
self.text3 = text[2]
super(MyPopup, self).open(**kwargs)
class Testapp(App):
def build(self):
return Builder.load_string('''
#:import F kivy.factory.Factory
<MyPopup>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Close me!'
on_release: root.dismiss()
TextInput:
text: root.text1
TextInput:
text: root.text2
TextInput:
text: root.text3
Button:
on_press: F.MyPopup().open(['Palim1', 'Palim2', 'Palim3'])
''')
Testapp().run()