test.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, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
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.maximize()
from kivy.clock import Clock
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
class EditStatePopup(Popup):
col_data = ListProperty(["?", "?", "?"])
index = NumericProperty(0)
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data[self.index]["StateId"]
self.col_data[1] = obj.rv_data[self.index]["StateName"]
self.col_data[2] = obj.rv_data[self.index]["StateCode"]
def package_changes(self, stateName, stateCode):
self.col_data[1] = stateName
self.col_data[2] = stateCode
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 __init__(self, **kwargs):
super(SelectableButton, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data[self.index][self.key]
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):
self.selected = is_selected
self.rv_data = rv.data
def on_press(self):
popup = EditStatePopup(self)
popup.open()
class RV(BoxLayout):
data_items = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
col3 = ListProperty()
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def update(self):
self.col1 = [{'StateId': str(x[0]), 'StateName': x[1], 'StateCode': str(x[2]), 'key': 'StateId'} for x in self.data_items]
self.col2 = [{'StateId': str(x[0]), 'StateName': x[1], 'StateCode': str(x[2]), 'key': 'StateName'} for x in self.data_items]
self.col3 = [{'StateId': str(x[0]), 'StateName': x[1], 'StateCode': str(x[2]), 'key': 'StateCode'} for x in self.data_items]
def get_states(self):
rows = [(1, 'Andaman and Nicobar Islands ', 35), (2, 'Andhra Pradesh', 28), (3, 'Arunachal Pradesh', 12), (4, 'Assam', 18), (5, 'Bihar', 10), (6, 'Chandigarh', 4), (7, 'Chattisgarh', 22)]
i = 0
for row in rows:
self.data_items.append([row[0], row[1], row[2], i])
i += 1
print(self.data_items)
self.update()
def populate_tree_view(tree_view, parent, node):
if parent is None:
tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
is_open=True))
else:
tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
is_open=True), parent)
for child_node in node['children']:
populate_tree_view(tree_view, tree_node, child_node)
rows = [(1, 'Andaman and Nicobar Islands ', 35), (2, 'Andhra Pradesh', 28), (3, 'Arunachal Pradesh', 12), (4, 'Assam', 18), (5, 'Bihar', 10), (6, 'Chandigarh', 4), (7, 'Chattisgarh', 22)]
tree = []
for r in rows:
tree.append({'node_id': r[1], 'children': []})
class TreeviewGroup(Popup):
treeview = ObjectProperty(None)
tv = ObjectProperty(None)
h = NumericProperty(0)
#ti = ObjectProperty()
def __init__(self, **kwargs):
super(TreeviewGroup, self).__init__(**kwargs)
self.tv = TreeView(root_options=dict(text=""),
hide_root=False,
indent_level=4)
for branch in tree:
populate_tree_view(self.tv, None, branch)
#self.remove_widgets()
self.treeview.add_widget(self.tv)
Clock.schedule_once(self.update, 1)
def remove_widgets(self):
for child in [child for child in self.treeview.children]:
self.treeview.remove_widget(child)
def update(self, *args):
self.h = len([child for child in self.tv.children]) * 24
class EditCityPopup(Popup):
col_data = ListProperty(["?", "?", "?", "?", "?"])
index = NumericProperty(0)
popup = ObjectProperty(None)
def __init__(self, obj, **kwargs):
super(EditCityPopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data_city[self.index]["cityId"]
self.col_data[1] = obj.rv_data_city[self.index]["stateId"]
self.col_data[2] = obj.rv_data_city[self.index]["cityName"]
self.col_data[3] = obj.rv_data_city[self.index]["shortName"]
self.col_data[4] = obj.rv_data_city[self.index]["pinCode"]
def package_changes(self, stateId, cityName, shortName, pinCode):
self.col_data[1] = stateId
self.col_data[2] = cityName
self.col_data[3] = shortName
self.col_data[4] = pinCode
def display_states_treeview(self, instance):
if len(instance.text) > 0:
if self.popup is None:
self.popup = TreeviewGroup()
self.popup.open()
class SelectableButtonCity(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data_city = ObjectProperty(None)
start_point = NumericProperty(0)
def __init__(self, **kwargs):
super(SelectableButtonCity, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data_city[self.index][self.key]
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButtonCity, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButtonCity, 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_city = rv.data
def on_press(self):
popup = EditCityPopup(self)
popup.open()
class RVCITY(BoxLayout):
data_items_city = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
col3 = ListProperty()
col4 = ListProperty()
col5 = ListProperty()
def __init__(self, **kwargs):
super(RVCITY, self).__init__(**kwargs)
self.get_cities()
def update(self):
self.col1 = [{'cityId': str(x[0]), 'stateId': str(x[1]), 'cityName': str(x[2]), 'shortName': str(x[3]), 'pinCode': str(x[4]), 'key': 'cityId'} for x in self.data_items_city]
self.col2 = [{'cityId': str(x[0]), 'stateId': str(x[1]), 'cityName': str(x[2]), 'shortName': str(x[3]), 'pinCode': str(x[4]), 'key': 'stateId'} for x in self.data_items_city]
self.col3 = [{'cityId': str(x[0]), 'stateId': str(x[1]), 'cityName': str(x[2]), 'shortName': str(x[3]), 'pinCode': str(x[4]), 'key': 'cityName'} for x in self.data_items_city]
self.col4 = [{'cityId': str(x[0]), 'stateId': str(x[1]), 'cityName': str(x[2]), 'shortName': str(x[3]), 'pinCode': str(x[4]), 'key': 'shortName'} for x in self.data_items_city]
self.col5 = [{'cityId': str(x[0]), 'stateId': str(x[1]), 'cityName': str(x[2]), 'shortName': str(x[3]), 'pinCode': str(x[4]), 'key': 'pinCode'} for x in self.data_items_city]
def get_cities(self):
rows = [(1, 'Bihar', 'Patna', 'Patna', 801108), (2, 'Andaman and Nicobar Islands ', 'Port Blair', 'PB', 744101), (3, 'Assam', 'Guwahati', 'Guwahati', 781001), (4, 'Assam', 'Nagaon', 'Nagaon', 782120), (5, 'Chandigarh', 'Amritsar', 'Amritsar', 143502), (6, 'Andhra Pradesh', 'Visakhapatnam', 'VP', 531219), (7, 'Chattisgarh', 'Bilaspur', 'Bilaspur', 495001)]
i = 0
for row in rows:
self.data_items_city.append([row[0], row[1], row[2], row[3], row[4], i])
i += 1
print(self.data_items_city)
self.update()
class EditAreaPopup(Popup):
col_data = ListProperty(["?", "?", "?"])
index = NumericProperty(0)
popup = ObjectProperty(None)
def __init__(self, obj, **kwargs):
super(EditAreaPopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data_area[self.index]["areaId"]
self.col_data[1] = obj.rv_data_area[self.index]["cityId"]
self.col_data[2] = obj.rv_data_area[self.index]["areaName"]
def package_changes(self, stateId, cityName):
self.col_data[1] = stateId
self.col_data[2] = cityName
def display_city_treeview(self, instance):
if len(instance.text) > 0:
if self.popup is None:
self.popup = TreeviewGroup()
#self.popup.filter(instance.text)
self.popup.open()
class SelectableButtonArea(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data_area = ObjectProperty(None)
start_point = NumericProperty(0)
def __init__(self, **kwargs):
super(SelectableButtonArea, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data_area[self.index][self.key]
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButtonArea, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButtonArea, 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_area = rv.data
#print("selection changed to {0}".format(rv.data[1]))
def on_press(self):
popup = EditAreaPopup(self)
popup.open()
class RVAREA(BoxLayout):
data_items_area = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
col3 = ListProperty()
def __init__(self, **kwargs):
super(RVAREA, self).__init__(**kwargs)
self.get_areas()
def update(self):
self.col1 = [{'areaId': str(x[0]), 'cityId': str(x[1]), 'areaName': str(x[2]), 'key': 'areaId'} for x in self.data_items_area]
self.col2 = [{'areaId': str(x[0]), 'cityId': str(x[1]), 'areaName': str(x[2]), 'key': 'cityId'} for x in self.data_items_area]
self.col3 = [{'areaId': str(x[0]), 'cityId': str(x[1]), 'areaName': str(x[2]), 'key': 'areaName'} for x in self.data_items_area]
def get_areas(self):
rows = [(1, 'Amritsar', 'area1')]
i = 0
for row in rows:
self.data_items_area.append([row[0], row[1], row[2], i])
i += 1
print(self.data_items_area)
self.update()
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
states_cities_or_areas = ObjectProperty()
rv = ObjectProperty(None)
dropdown = ObjectProperty(None)
#Define City Variable
rvcity = ObjectProperty(None)
#Area City Variable
rvarea = ObjectProperty(None)
def display_states(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rv = RV()
self.states_cities_or_areas.add_widget(self.rv)
def display_cities(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvcity = RVCITY()
self.states_cities_or_areas.add_widget(self.rvcity)
def display_areas(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvarea = RVAREA()
self.states_cities_or_areas.add_widget(self.rvarea)
def remove_widgets(self):
self.states_cities_or_areas.clear_widgets()
class FactApp(App):
title = "test"
def build(self):
self.root = Builder.load_file('test.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
test.kv
#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os
<EditStatePopup>:
title: "Update State"
size_hint: None, None
size: 500, 200
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
Label:
text: "Id"
Label:
id: stateId
text: root.col_data[0]
Label:
text: "State Name"
TextInput:
id: stateName
text: root.col_data[1]
Label:
text: "State Code"
TextInput:
id: stateCode
text: root.col_data[2]
Button:
size_hint: 1, 1
text: "Ok"
on_release:
root.package_changes(stateName.text, stateCode.text)
app.root.update_states(root)
root.dismiss()
Button:
size_hint: 1, 1
text: "Cancel"
on_release: root.dismiss()
<TreeViewLabel>:
size_hint_y: None
height: 24
on_touch_down:
app.root.stateName.text = self.text
app.root.popup.dismiss()
<TreeviewGroup>:
id: treeview
treeview: treeview
title: "Select State"
size_hint: .3,.3
size: 800, 800
auto_dismiss: False
BoxLayout
orientation: "vertical"
ScrollView:
size_hint: 1, .9
BoxLayout:
size_hint_y: None
id: treeview
height: root.h
Button:
size_hint: 1, 0.1
text: "Close"
on_release: root.dismiss()
<SelectableButton>:
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
<MyRV#RecycleView>:
viewclass: 'SelectableButton'
SelectableRecycleGridLayout:
cols: 1
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
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Id"
Label:
size_hint_x: .5
text: "State Name"
Label:
size_hint_x: .4
text: "State Code"
BoxLayout:
MyRV:
size_hint_x: .1
data: root.col1
MyRV:
size_hint_x: .5
data: root.col2
MyRV:
size_hint_x: .4
data: root.col3
<EditCityPopup>:
title: "Update State"
size_hint: None, None
size: 500, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
Label:
text: "City Id"
Label:
id: cityId
text: root.col_data[0]
Label:
text: "State Id"
TextInput:
id: stateId
text: root.col_data[1]
on_focus: root.display_states_treeview(self)
Label:
text: "city Name"
TextInput:
id: cityName
text: root.col_data[2]
Label:
text: "Short Name"
TextInput:
id: shortName
text: root.col_data[3]
Label:
text: "Pin Code"
TextInput:
id: pinCode
text: root.col_data[4]
Button:
size_hint: 1, 1
text: "Ok"
on_release:
root.package_changes(stateId.text, cityName.text, shortName.text, pinCode.text)
app.root.update_cities(root)
root.dismiss()
Button:
size_hint: 1, 1
text: "Cancel"
on_release: root.dismiss()
<MyRvCity#RecycleView>:
viewclass: 'SelectableButtonCity'
SelectableRecycleGridLayout:
cols: 1
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
<RVCITY>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y:None
height: 25
cols: 5
Label:
size_hint_x: .1
text: "City Id"
Label:
size_hint_x: .2
text: "State Name"
Label:
size_hint_x: .3
text: "City Name"
Label:
size_hint_x: .2
text: "Short Name"
Label:
size_hint_x: .2
text: "Pin Code"
BoxLayout:
MyRvCity:
size_hint_x: .1
data: root.col1
MyRvCity:
size_hint_x: .2
data: root.col2
MyRvCity:
size_hint_x: .3
data: root.col3
MyRvCity:
size_hint_x: .2
data: root.col4
MyRvCity:
size_hint_x: .2
data: root.col5
<EditAreaPopup>:
title: "Update State"
size_hint: None, None
size: 500, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
Label:
text: "City Id"
Label:
id: cityId
text: root.col_data[0]
Label:
text: "State Id"
TextInput:
id: stateId
text: root.col_data[1]
on_focus: root.display_states_treeview(self)
Label:
text: "city Name"
TextInput:
id: cityName
text: root.col_data[2]
Button:
size_hint: 1, 1
text: "Ok"
on_release:
root.package_changes(stateId.text, cityName.text, shortName.text, pinCode.text)
app.root.update_cities(root)
root.dismiss()
Button:
size_hint: 1, 1
text: "Cancel"
on_release: root.dismiss()
<MyRvArea#RecycleView>:
viewclass: 'SelectableButtonArea'
SelectableRecycleGridLayout:
cols: 1
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
<RVAREA>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Area Id"
Label:
size_hint_x: .5
text: "City Name"
Label:
size_hint_x: .4
text: "Area Name"
BoxLayout:
MyRvArea:
size_hint_x: .1
data: root.col1
MyRvArea:
size_hint_x: .5
data: root.col2
MyRvArea:
size_hint_x: .4
data: root.col3
<DropdownButton#Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
background_color: 90 , 90, 90, 90
color: 0, 0.517, 0.705, 1
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states_cities_or_areas: states_cities_or_areas
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'Test1'
size_hint_y: None
height: '32dp'
on_release: root.display_states()
DropdownButton:
text: 'Test2'
size_hint_y: None
height: '32dp'
on_release: root.display_cities()
DropdownButton:
text: 'Test3'
size_hint_y: None
height: '32dp'
on_release: root.display_areas()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
Label:
size_hint_x: 45
BoxLayout:
id: states_cities_or_areas
size_hint_y: 10
Label:
size_hint_y: 1
Can anyone help me?
When i click on test then sub menu will be open.When i click on state then it look like good.But i click on city then distance increase between 'Test' and Row.
when i click on 'city' then show rows of city.when i click on any row then it looks Select state(treeview) show behind of 'update state'
I want it up on update state when anyone type anything in 'state Id'
i am using treeview in select state.how to add scrollbar in select state.when state increase then scroll will be good option
After update code I have a more error.
1. When i select state from select state then it's not put that string in state Name.Its showing error
File "/usr/share/kivy-examples/gst_fact/test.kv", line 50, in
app.root.stateName.text = self.text
AttributeError: 'MainMenu' object has no attribute 'stateName'
I want to when i click on anyone(state,city,area) then row show top position like Image_1.
It's because you have set the rules of your main menu in your kv to reserve the space for each box city, state and area. You can remove these rules and add only one box which I called states_cities_or_areas:
...
<MainMenu>:
states_cities_or_areas: states_cities_or_areas
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 5
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'State'
size_hint_y: None
height: '32dp'
on_release: root.display_states()
DropdownButton:
text: 'City'
size_hint_y: None
height: '32dp'
on_release: root.display_cities()
DropdownButton:
text: 'Area'
size_hint_y: None
height: '32dp'
on_release: root.display_areas()
BoxLayout:
size_hint_y: 2.5
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
Label:
size_hint_x: 45
BoxLayout:
id: states_cities_or_areas
size_hint_y: 89
Label:
size_hint_y: 1
...
then change some methods and attributes of the mainmenu in the .py:
...
class MainMenu(BoxLayout):
states_cities_or_areas = ObjectProperty()
rv = ObjectProperty(None)
dropdown = ObjectProperty(None)
#Define City Variable
rvcity = ObjectProperty(None)
#Area City Variable
rvarea = ObjectProperty(None)
def display_states(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rv = RV()
self.states_cities_or_areas.add_widget(self.rv)
def display_cities(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvcity = RVCITY()
self.states_cities_or_areas.add_widget(self.rvcity)
def display_areas(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvarea = RVAREA()
self.states_cities_or_areas.add_widget(self.rvarea)
def remove_widgets(self):
self.states_cities_or_areas.clear_widgets()
...
I have noticed that the tiles of colums of city was not displayed, you can display it with this in the kv:
...
<RVCITY>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 5
...
when i click on 'city' then show rows of city.when i click on any row then it looks Select state(treeview) show behind of 'update state' like image_4 I want it up on update state when anyone type anything in 'state Id' like image_5
It's because the StateId text input is already on_text before the the popup opens. I suggest you to replace on_text with on_focus:
...
<EditCityPopup>:
title: "Update State"
size_hint: None, None
size: 500, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
Label:
text: "City Id"
Label:
id: cityId
text: root.col_data[0]
Label:
text: "State Id"
TextInput:
id: stateId
text: root.col_data[1]
on_focus: root.display_states_treeview(self)
...
i am using treeview in select state.how to add scrollbar in select state.when state increase then scroll will be good option
You just have to put the treeview in a scrollview:
...
<TreeViewLabel>:
size_hint_y: None
height: 24
on_touch_down:
app.root.stateName.text = self.text
app.root.select_node(self)
app.root.popup.dismiss()
<TreeviewGroup>:
treeview: treeview
title: "Select State"
size_hint: .3,.3
auto_dismiss: False
BoxLayout
orientation: "vertical"
ScrollView:
size_hint: 1, .9
BoxLayout:
size_hint_y: None
id: treeview
height: root.h
Button:
size_hint: 1, 0.1
text: "Close"
on_release: root.dismiss()
and in the .py:
...
class TreeviewGroup(Popup):
treeview = ObjectProperty(None)
tv = ObjectProperty(None)
h = NumericProperty(0)
#ti = ObjectProperty()
def __init__(self, **kwargs):
super(TreeviewGroup, self).__init__(**kwargs)
self.tv = TreeView(root_options=dict(text=""),
hide_root=True,
indent_level=4)
for branch in tree:
populate_tree_view(self.tv, None, branch)
#self.remove_widgets()
self.treeview.add_widget(self.tv)
Clock.schedule_once(self.update, 1)
def remove_widgets(self):
for child in [child for child in self.treeview.children]:
self.treeview.remove_widget(child)
def update(self, *args):
self.h = len([child for child in self.tv.children]) * 24
Update
FOR THE 4TH POINT;
to pass the stateName to the other popup,keep the instance of the first popup when you create the 2nd:
...
class TreeviewGroup(Popup):
treeview = ObjectProperty(None)
tv = ObjectProperty(None)
h = NumericProperty(0)
#ti = ObjectProperty()
popup = ObjectProperty()
...
class EditCityPopup(Popup):
...
def display_states_treeview(self, instance):
if len(instance.text) > 0:
if self.popup is None:
self.popup = TreeviewGroup()
self.popup.popup = self
self.popup.open()
To reach the first popup in the kv make those changes:
in the .py:
...
class MyBoxLayout(BoxLayout):
rooot = ObjectProperty()
...
In the kv:
...
<TreeViewLabel>:
size_hint_y: None
height: 24
on_touch_down:
root.parent.parent.rooot.popup.col_data[1] = self.text
#app.root.select_node(self)
root.parent.parent.rooot.popup.popup.dismiss()
<TreeviewGroup>:
id: treeview
treeview: treeview
title: "Select State"
size_hint: .3,.3
size: 800, 800
auto_dismiss: False
BoxLayout
orientation: "vertical"
ScrollView:
size_hint: 1, .9
MyBoxLayout:
size_hint_y: None
id: treeview
height: root.h
rooot: root
...
Related
So I have managed to get widgets of varying height into a recycleview and items can be added, this looked perfect on my PC but was very wrong when running on android. I re-built the app with buildozer to make sure it wasn't something to do with that, I put together the demo program seen below and ran it on both platforms, and experienced the same result. I have used the kivy inspector and not been able to see any values that are not what I didn't manually program. And unless I have missed one I have used dp(X) or 'Xdp' whenever needed.
Any help or tips will be apreciated, thank you :)
main.py
from random import randint
from kivy.app import App
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.graphics import Color, Rectangle
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty, NumericProperty
class NewPostGrid(BoxLayout):
votes_ = StringProperty()
message_id_ = StringProperty()
text_ = StringProperty()
group_ = StringProperty()
_size = ListProperty()
class SizeLabel(Label):
pass
class RV(RecycleView):
distance_to_top = NumericProperty()
scrollable_distance = NumericProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.get_running_app().rv_data_list = []
def generate_post(self): # This is only to test posts with different line height
e = ['Test post ID: ', str(App.get_running_app().message_id_num)]
for i in range(randint(1, 8)): e.append('\n')
e.append('end of post')
return "".join(e)
def add(self):
l = len(App.get_running_app().rv_data_list)
text = self.generate_post()
sl = SizeLabel(text=text)
sl.texture_update()
print(sl.text)
App.get_running_app().rv_data_list.extend([{'message_id_': str(App.get_running_app().message_id_num),
'text_': text,
'_size': sl.texture_size,
'group_': str(App.get_running_app().message_id_num),
'votes_': str(20)}])
App.get_running_app().message_id_num = App.get_running_app().message_id_num + 1
def on_scrollable_distance(self, *args):
if self.scroll_y > 0:
self.scroll_y = (self.scrollable_distance - self.distance_to_top) / self.scrollable_distance
def on_scroll_y(self, *args):
self.distance_to_top = (1 - self.scroll_y) * self.scrollable_distance
#def adjust_vote_state(self, id_):
# for d in self.data:
# if d['text_'] == id_.text_:
# d['state'] == id_.ids.button_up.state
# id_.state = id_.ids.button_up.state
class DemoApp(App):
# One post format = {'message_id':0, 'text':'post_test_here','_size':[0,0], '_group':str(0), '_score':20}
# Text fromat string = [font=Nunito-Bold.ttf][color=161616]Someone:[/color][/font]\n
message_id_num = 0
rv_data_list = ListProperty()
pending_data = ListProperty()
def build(self):
#Clock.schedule_interval(self.add_log, .01)
Clock.schedule_interval(self.flush_pending_data, .250)
def up_vote(self, button, mode): # Not part of the problem
if button.state == 'down':
if mode == 'all':
print("+1 upvote for message index:" + str(button.parent.parent.message_id) + ' in all posts')
else:
print("+1 upvote for message index:" + str(button.parent.parent.message_id) + ' in top posts')
def down_vote(self, button, mode): # Not part of the problem
if button.state == 'down':
if mode == 'all':
print("-1 upvote for message index:" + str(button.parent.parent.message_id) + ' in all posts')
else:
print("-1 upvote for message index:" + str(button.parent.parent.message_id) + ' in top posts')
def flush_pending_data(self, *args):
if self.pending_data:
pending_data, self.pending_data = self.pending_data, []
self.rv_data_list.extend(pending_data)
def generate_post(self): # This is only to test posts with different line height
e = ['Test post ID: ', str(self.message_id_num)]
for i in range(randint(1, 8)): e.append('\n')
e.append('end of post')
return "".join(e)
def add_log(self, dt):
for i in range(10):
text = self.generate_post()
sl = SizeLabel(text=text)
sl.texture_update()
self.pending_data.append({'message_id_': str(self.message_id_num),
'text_': text,
'_size': sl.texture_size,
'group_': str(self.message_id_num),
'votes_': str(20)})
self.message_id_num = self.message_id_num + 1
if __name__ == '__main__':
DemoApp().run()
demo.kv
<SizeLabel>:
padding: "10dp", "12dp"
size_hint: 0.9, None
height: self.texture_size[1]
font_size: "12dp"
text_size: self.width, None
color: 0,0,0,1
multiline: True
markup: True
<NewPostGrid>:
spacing: "6dp"
message_id: root.message_id_
BoxLayout:
id: voting_menu
orientation: "vertical"
spacing: "2dp"
size_hint: .2, None
height: label.height
ToggleButton:
id: button_up
on_state: app.up_vote(self, 'all')
group: root.group_
#state: root.vote_state_up
text: "UP"
color: (1,1,1,1) if self.state=='normal' else (.8,0,0,1)
font_size: "10dp"
size_hint: 1, .3
background_color: .2, .2, .2, 0
#on_release: app.root.ids.rv.adjust_vote_state(root)
canvas.before:
Color:
rgba: (.1,.1,.1,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [6,]
canvas:
Color:
rgba: (.2,.2,.2,1)
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
Label:
id: vote_count
text: root.votes_
size_hint: 1, .4
multiline: False
ToggleButton:
id: button_down
on_state: app.down_vote(self, 'all')
group: root.group_
#state: root.vote_state_down
text: "DOWN"
color: (1,1,1,1) if self.state=='normal' else (.8,0,0,1)
font_size: "10dp"
size_hint: 1, .3
background_color: .2, .2, .2, 0
canvas.before:
Color:
rgba: (.1,.1,.1,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [6,]
canvas:
Color:
rgba: (.2,.2,.2,1)
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
Label:
id: label
text: root.text_
padding: "10dp", "12dp"
size_hint: .9, None
height: self.texture_size[1]
font_size: "12dp"
text_size: self.width, None
color: 0,0,0,1
multiline: True
markup: True
#on_texture_size: root.update_message_size(root.message_id, self.texture_size)
pos: self.x, self.y
canvas.before:
Color:
rgba: (0.8, 0.8, 0.8, 1)
RoundedRectangle:
size: self.texture_size
radius: [5, 5, 5, 5]
pos: self.x, self.y
canvas:
Color:
rgba:0.8,0,0,1
Line:
width: 1.4
rounded_rectangle:(self.x,self.y,self.width,self.height, 5)
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, .1
orientation: 'horizontal'
Button:
text: 'Add widget to RV list'
on_release: rv.add()
ToggleButton:
id: active
text: 'active'
on_state: app.add_log(self)
RV:
id: rv
viewclass: 'NewPostGrid' # The view class is TwoButtons, defined above.
data: app.rv_data_list # the data is a list of dicts defined below in the RV class.
scroll_type: ['bars', 'content']
#on_scroll_y: app.fill_data(self, box)
scrollable_distance: box.height - self.height
bar_width: dp(2)
RecycleBoxLayout:
id: box
# This layout is used to hold the Recycle widgets
# default_size: None, dp(48) # This sets the height of the BoxLayout that holds a TwoButtons instance.
key_size: '_size'
default_size_hint: 1, None
size_hint_y: None
spacing: '16dp'
height: self.minimum_height # To scroll you need to set the layout height.
orientation: 'vertical'
padding: ['10dp', '20dp']
Image of app running on windows
Video of app running on android
Video of full app running (The code for the recycleview is identical)
I have two file demo.py and demo.kv.
When i run demo.py and click on +Add then screen shows looks like.I want value of name textbox in def add_row(self): function when click on button.When i click on button of first row then i want to get test1 in def add_row(self): which are in class RowsExtra(BoxLayout): and click on button of second row then get test2.I want to get test1 value in textName variable.After that i am fetching data from database according name textbox value.
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
textName = 'test1'
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
demo.py
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.uix.popup import Popup
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 400)
class User(Popup):
total_value = ObjectProperty(None)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
def add_more(self):
self.ids.rows.add_more()
class ExtraPopup(Popup):
mode = StringProperty("")
def __init__(self, obj, **kwargs):
super(ExtraPopup, self).__init__(**kwargs)
def add_extra(self):
self.ids.rowsExtra.add_row()
class RowExtra(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?", "?", "?", "?"])
button_text = StringProperty("")
mode = StringProperty("")
def __init__(self, **kwargs):
super(RowExtra, self).__init__(**kwargs)
self.col_data[0] = ''
self.col_data[1] = ''
self.col_data[2] = ''
class RowsExtra(BoxLayout):
#orientation = "vertical"
row_count = 0
button_text = StringProperty("")
def __init__(self, **kwargs):
super(RowsExtra, self).__init__(**kwargs)
self.add_row()
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
textName = 'test1'
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
name = ObjectProperty(None)
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
def add_seller_expenses(self):
self.mode = "Add"
popup = ExtraPopup(self)
popup.open()
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_more()
def add_more(self):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
class rv(BoxLayout):
data_items = ListProperty([])
mode = StringProperty("")
def __init__(self, **kwargs):
super(rv, self).__init__(**kwargs)
def add(self):
self.mode = "Add"
popup = User()
popup.open()
class MainMenu(BoxLayout):
content_area = ObjectProperty()
def display(self):
self.rv = rv()
self.content_area.add_widget(self.rv)
class demo(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
demo().run()
demo.kv
<Row>:
size_hint_y: None
height: self.minimum_height
height: 40
Button:
text: root.button_text
size_hint_x: None
top: 200
TextInput:
id : name
text: root.col_data3
width: 300
TextInput:
id: number_input
text: root.col_data4
width: 300
input_filter: 'int'
Button:
text: "Button"
size_hint_x: None
top: 200
on_press: root.add_seller_expenses()
<Rows>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<User>:
id: user
BoxLayout:
orientation: "vertical"
padding : 20, 5
BoxLayout:
orientation: "horizontal"
#padding : 10, 10
spacing: 10, 10
size: 450, 40
size_hint: None, None
Label:
size_hint_x: .2
text: "Number"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "name"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "Value"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
size_hint_x: .2
size_hint_y: .2
Button:
text: "+Add More"
on_press: root.add_more()
<rv>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: .25, .03
text: "+Add"
on_press: root.add()
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
BoxLayout:
orientation: "vertical"
<ExtraPopup>:
title: " Extra"
title_size: 20
title_font: "Verdana"
size_hint: None, None
size: 400, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
padding : 10, 5
spacing: 10, 10
BoxLayout:
orientation: "horizontal"
spacing: 10, 10
size: 550, 30
size_hint: 1, None
Label:
size_hint_x: .3
text: "SN"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .7
text: "Name"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
RowsExtra:
id: rowsExtra
BoxLayout:
orientation: "horizontal"
size_hint_x: .3
size_hint: .15, .1
Button:
#size_hint_x: .2
text: "+Add More"
valign: 'bottom'
on_press: root.add_extra()
BoxLayout:
orientation: "horizontal"
padding : 10, 5
spacing: 10, 10
size_hint: .5, .2
pos_hint: {'x': .25, 'y':.25}
Button:
text: 'Ok'
id: ok_text
on_release:
root.dismiss()
Button:
text: 'Cancel'
#size_hint_x: .5
on_release: root.dismiss()
<RowExtra>:
size_hint_y: None
height: self.minimum_height
height: 30
Button:
text: root.button_text
size_hint_x: .3
#top: 200
TextInput:
text: root.col_data[1]
size_hint_x: .7
<RowsExtra>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (100, 40)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
content_area: content_area
BoxLayout:
orientation: 'vertical'
spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 2
MenuButton:
text: 'Menu'
size : (50, 12)
on_release: root.display()
BoxLayout:
id: content_area
size_hint_y: 30
A possible solution is to access rowsExtra through the popup since it is your child, but one problem is that you call add_row() in the constructor before it is assigned a parent (the assignment of a parent is after the creation of the object), we must eliminate that instruction and call it again before opening the popup. To store the text we can create a property of type StringProperty.
[...]
class RowsExtra(BoxLayout):
#orientation = "vertical"
row_count = 0
button_text = StringProperty("")
textName = StringProperty("")
def __init__(self, **kwargs):
super(RowsExtra, self).__init__(**kwargs)
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
print(self.textName)
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
name = ObjectProperty(None)
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
def add_seller_expenses(self):
self.mode = "Add"
popup = ExtraPopup(self)
popup.ids.rowsExtra.textName = self.ids.name.text
popup.ids.rowsExtra.add_row()
popup.open()
[...]
test.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, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
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 = (900, 500)
MAX_TABLE_COLS = 3
con = lite.connect('demo.db')
con.text_factory = str
cur = con.cursor()
class EditStatePopup(Popup):
col_data = ListProperty(["?", "?", "?"])
index = NumericProperty(0)
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data[self.index]["Id"]
self.col_data[1] = obj.rv_data[self.index]["Name"]
self.col_data[2] = obj.rv_data[self.index]["Code"]
def package_changes(self, stateName, stateCode):
self.col_data[1] = stateName
self.col_data[2] = stateCode
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 __init__(self, **kwargs):
super(SelectableButton, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data[self.index][self.key]
def on_press(self):
popup = EditStatePopup(self)
popup.open()
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
#print("selection changed to {0}".format(rv.data[1]))
class RV(BoxLayout):
data_items = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
col3 = ListProperty()
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def update(self):
self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Id'} for x in self.data_items]
self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Name'} for x in self.data_items]
self.col3 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Code'} for x in self.data_items]
def get_states(self):
rows = [(1, 'Yash', 'Chopra'), (2, 'amit', 'Kumar')]
# create data_items
i = 0
for row in rows:
self.data_items.append([row[0], row[1], row[2], i])
i += 1
self.update()
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
rv = ObjectProperty(None)
states = ObjectProperty(None)
dropdown = ObjectProperty(None)
def display_states(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rv = RV()
self.states.add_widget(self.rv)
def remove_widgets(self):
for child in [child for child in self.states.children]:
self.states.remove_widget(child)
def update_states(self, obj):
# update data_items
# obj.start_point + 1 --- skip State_ID
self.rv.data_items[obj.index] = [ obj.col_data[0], obj.col_data[1], obj.col_data[2], obj.index]
self.rv.update()
# update Database Table
cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",
(obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
class TestApp(App):
title = "test"
def build(self):
self.root = Builder.load_file('test.kv')
return MainMenu()
if __name__ == '__main__':
TestApp().run()
test.kv
#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os
<EditStatePopup>:
title: "Update State"
size_hint: None, None
size: 300, 300
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: "Id"
Label:
id: Id
text: root.col_data[0]
Label:
text: "Name"
TextInput:
id: Name
text: root.col_data[1]
Label:
text: "Code"
TextInput:
id: stateCode
text: root.col_data[2]
Button:
size_hint: 1, 0.4
text: "Cancel"
on_release: root.dismiss()
Button:
size_hint: 1, 0.4
text: "Ok"
on_release:
root.package_changes(Name.text, Code.text)
#root.obj.update_states(root.start_point, root.max_table_cols, root.new_data)
app.root.update_states(root)
root.dismiss()
<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
<MyRV#RecycleView>:
viewclass: 'SelectableButton'
SelectableRecycleGridLayout:
cols: 1
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
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Id"
Label:
size_hint_x: .5
text: "Name"
Label:
size_hint_x: .4
text: "Code"
BoxLayout:
MyRV:
size_hint_x: .1
data: root.col1
MyRV:
size_hint_x: .5
data: root.col2
MyRV:
size_hint_x: .4
data: root.col3
<DropdownButton#Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
#on_release: dropdown.select('')
#on_release: app.root.test
background_color: 90 , 90, 90, 90
color: 0, 0.517, 0.705, 1
#<CustDrop>:
#id: dropdown
#auto_width: False
#width: 150
#DropdownButton:
#text: 'Add State'
#on_release: os.system("python m_State.py")
#DropdownButton:
#text: 'List State'
#on_release: root.display_users()
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states: states
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Menu'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'user'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_states()
BoxLayout:
id: states
size_hint_y: 9
Label:
size_hint_y: 9
When i click on menu then show sub menu user.when click on user then show list of user when i click on any row of user then show error IndexError: list index out of range.
update_states() function does not update in database
1.When i click on menu then show sub menu user.when click on user then show list of user when i click on any row of user then show error like attached image.
You are iterating over rows, you have only two rows but 3 columns
update_states() function does not update in database
I don't think that the compilator terminates that function because there are few errors in it
To get your code works I had to make many changes
First prepare the data of the rvs in the python file
...
class RV(BoxLayout):
data_items = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
col3 = ListProperty()
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def update(self):
self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Id'} for x in self.data_items]
self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Name'} for x in self.data_items]
self.col3 = [{'Id': str(x[0]), 'Name': x[1], 'Code': x[2], 'key': 'Code'} for x in self.data_items]
def get_states(self):
#cur.execute("SELECT * FROM `m_state` order by state_id asc")
#rows = cur.fetchall()
rows = [(1, 'Yash', 'Chopra'), (2, 'amit', 'Kumar')]
# create data_items
'''for row in rows:
for col in row:
self.data_items.append(col)'''
i = 0
for row in rows:
self.data_items.append([row[0], row[1], row[2], i])
i += 1
self.update()
...
then in the kv replace the data of the rvs by col1, col2, col3 respectively
...
<RV>:
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Id"
Label:
size_hint_x: .5
text: "Name"
Label:
size_hint_x: .4
text: "Code"
BoxLayout:
MyRV:
size_hint_x: .1
data: root.col1
MyRV:
size_hint_x: .5
data: root.col2
MyRV:
size_hint_x: .4
data: root.col3
...
To change automatically the text of the buttons of the rvs when you edit them I had to schedule a function
...
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 __init__(self, **kwargs):
super(SelectableButton, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data[self.index][self.key]
...
def on_press(self):
popup = EditStatePopup(self)
popup.open()
...
You have also to edit the EditStatePopup, I add the index attribute because It will be much easier to make change in the mainmenu with him
...
class EditStatePopup(Popup):
col_data = ListProperty(["?", "?", "?"])
index = NumericProperty(0)
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data[self.index]["Id"]
self.col_data[1] = obj.rv_data[self.index]["Name"]
self.col_data[2] = obj.rv_data[self.index]["Code"]
Finally edit the updtate_states of the MainMenu class:
...
class MainMenu(BoxLayout):
...
def update_states(self, obj):
# update data_items
# obj.start_point + 1 --- skip State_ID
self.rv.data_items[obj.index] = [ obj.col_data[0], obj.col_data[1], obj.col_data[2], obj.index]
self.rv.update()
# update Database Table
cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",
(obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
Please be careful when making those changes. I hope this helps
menu.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.dropdown import DropDown
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
import sys
#Window.borderless = True
#Window.clearcolor = (0, 0.517, 0.705, 1)
Window.size = (900, 500)
#from easygui import msgbox
#db =lite.connect(':memory:')
con = lite.connect('test.db')
con.text_factory = str
cur = con.cursor()
class EditStatePopup(Popup):
obj = ObjectProperty(None)
start_point = NumericProperty(0)
max_table_cols = NumericProperty(0)
new_data = ListProperty([])
stateId = StringProperty("")
stateName = StringProperty("")
stateCode = StringProperty("")
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.obj = obj
self.start_point = obj.start_point
self.max_table_cols = obj.max_table_cols
self.stateId = obj.rv_data[obj.start_point]["text"]
self.stateName = obj.rv_data[obj.start_point + 1]["text"]
self.stateCode = obj.rv_data[obj.start_point + 2]["text"]
def package_changes(self, stateId, stateName, stateCode):
print(stateName)
self.new_data.append(stateId)
self.new_data.append(stateName)
self.new_data.append(stateCode)
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)
max_table_cols = NumericProperty(3)
data_items = ListProperty([])
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
#print("selection changed to {0}".format(rv.data[1]))
def on_press(self):
end_point = self.max_table_cols
rows = len(self.rv_data) # self.max_table_cols
#print(end_point) // 3
#print(rows) // 3
for row in range(rows):
cols = list(range(end_point))
#print(cols) // [0, 1, 2]
#print(self.index) //1
#print(self.max_table_cols)//3
if self.index in cols:
break
self.start_point += self.max_table_cols
end_point += self.max_table_cols
popup = EditStatePopup(self)
popup.open()
def update_states(self, stateId, stateName, stateCode):
cur.execute("UPDATE m_state SET state_name=?, state_code=? WHERE state_id=?",(stateName, stateCode, stateId))
con.commit()
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def get_states(self):
cur.execute("SELECT * FROM `m_state` order by state_id asc")
rows = cur.fetchall()
#print(rows)
# create data_items
rows = [(1, 'Test', '01'), (2, 'test2', '02'), (2, 'test2', '03')]
for row in rows:
for col in row:
self.data_items.append(col)
#print(col)
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
states = ObjectProperty(None)
dropdown = ObjectProperty(None)
def display_states(self):
# rv = RV()
self.dropdown.dismiss()
self.states.add_widget(RV())
#return CustDrop()
class FactApp(App):
title = "Test"
def build(self):
self.root = Builder.load_file('m_ListState.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
m_ListState.kv
#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os
<EditStatePopup>:
title: "Update State"
size_hint: None, None
size: 300, 300
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: "Id"
Label:
id: stateId
text: root.stateId
Label:
text: "Name"
TextInput:
id: stateName
text: root.stateName
Label:
text: "Code"
TextInput:
id: stateCode
text: root.stateCode
Button:
size_hint: 1, 0.4
text: "Cancel"
on_release: root.dismiss()
Button:
size_hint: 1, 0.4
text: "Ok"
on_release:
root.package_changes(stateId.text, stateName.text, stateCode.text)
#root.obj.update_states(root.start_point, root.max_table_cols, root.new_data)
root.obj.update_states(stateId.text, stateName.text, stateCode.text)
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: "Name"
Label:
text: "Code"
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
<DropdownButton#Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
background_color: 90 , 90, 90, 90
color: 0, 0.517, 0.705, 1
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states: states
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'View'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'State'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_states()
DropdownButton:
text: 'City'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_city()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
AsyncImage:
source: "add.jpg"
#on_release: os.system("python m_State.py")
Label:
size_hint_x: 22
BoxLayout:
id: states
size_hint_y: 9
Label:
size_hint_y: 9
Can anyone help for resolve some issue??
1. when i click on state (submenu of view) again and again then data repeats.How to avoid it.When i click on state then state list should be show and when i click on city then city list should be show.display_city() i have not written yet this for only example.
2. When i click on cancel two times then it shows error IndexError: list index out of range.
3.When i update state then it updated in database but does not change real time on screen.If i again run then shows updated data.
Please refer to the problems, solutions and example to solve your problems.
Columns Repeated
Problem
Each time you clicked View, widgets are dynamically added. If you clicked View twice, the columns are repeated twice.
Solution
You have to remove the widgets each time before adding them dynamically.
def display_states(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rv = RV()
self.states.add_widget(self.rv)
def remove_widgets(self):
for child in [child for child in self.states.children]:
self.states.remove_widget(child)
IndexError
Problem
Whenever you clicked on each row of data, it invokes the on_press method. The self.start_point is initialized at the beginning when the class SelectableButton is instantiated.
Solution
Initialize self.start_point in the on_press method.
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):
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = EditStatePopup(self)
popup.open()
RecycleView Not Updated
Problem
In the method update_states, RecycleView's data update is missing.
Solution
Add the following to update RecycleView's data.
def update_states(self, obj):
# update data_items
# obj.start_point + 1 --- skip State_ID
for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
self.rv.data_items[index] = obj.col_data[index - obj.start_point]
# update Database Table
cur.execute("UPDATE m_state SET State_Name=?, State_Code=? WHERE State_ID=?",
(obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
Example
m_ListState.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, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
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
import sys
#Window.borderless = True
#Window.clearcolor = (0, 0.517, 0.705, 1)
Window.size = (900, 500)
#from easygui import msgbox
MAX_TABLE_COLS = 3
path = "/home/iam/dev/SQLite/sampleDB/StateCodesNamesDB/"
#db =lite.connect(':memory:')
# con = lite.connect('fact.db')
con = lite.connect(path + 'country.db')
con.text_factory = str
cur = con.cursor()
class EditStatePopup(Popup):
start_point = NumericProperty(0)
col_data = ListProperty(["?", "?", "?"])
def __init__(self, obj, **kwargs):
super(EditStatePopup, 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, stateName, stateCode):
self.col_data[1] = stateName
self.col_data[2] = stateCode
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):
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = EditStatePopup(self)
popup.open()
class RV(BoxLayout):
data_items = ListProperty([])
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def get_states(self):
cur.execute("SELECT * FROM m_state order by State_ID asc")
rows = cur.fetchall()
# create data_items
for row in rows:
for col in row:
self.data_items.append(col)
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
rv = ObjectProperty(None)
states = ObjectProperty(None)
dropdown = ObjectProperty(None)
def display_states(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rv = RV()
self.states.add_widget(self.rv)
def remove_widgets(self):
for child in [child for child in self.states.children]:
self.states.remove_widget(child)
def update_states(self, obj):
# update data_items
# obj.start_point + 1 --- skip State_ID
for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
self.rv.data_items[index] = obj.col_data[index - obj.start_point]
# update Database Table
cur.execute("UPDATE m_state SET State_Name=?, State_Code=? WHERE State_ID=?",
(obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
class FactApp(App):
title = "Test"
def build(self):
self.root = Builder.load_file('m_ListState.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
m_ListState.kv
#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os
<EditStatePopup>:
title: "Update State"
size_hint: None, None
size: 300, 300
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: "Id"
Label:
id: stateId
text: root.col_data[0]
Label:
text: "Name"
TextInput:
id: stateName
text: root.col_data[1]
Label:
text: "Code"
TextInput:
id: stateCode
text: root.col_data[2]
Button:
size_hint: 1, 0.4
text: "Cancel"
on_release: root.dismiss()
Button:
size_hint: 1, 0.4
text: "Ok"
on_release:
root.package_changes(stateName.text, stateCode.text)
app.root.update_states(root)
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: "Name"
Label:
text: "Code"
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
<DropdownButton#Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
background_color: 90 , 90, 90, 90
color: 0, 0.517, 0.705, 1
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states: states
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'View'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'State'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_states()
DropdownButton:
text: 'City'
size_hint_y: None
height: '32dp'
#on_release: dropdown3.open(self)
on_release: root.display_city()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
AsyncImage:
source: "clipboard.jpeg" # "gst_image/add.jpg"
#on_release: os.system("python m_State.py")
Label:
size_hint_x: 22
BoxLayout:
id: states
size_hint_y: 9
Label:
size_hint_y: 9
Output
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.label import Label
from kivy.properties import ObjectProperty
Window.size = (700, 530)
def populate_tree_view(tree_view, parent, node):
if parent is None:
tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
is_open=True))
else:
tree_node = tree_view.add_node(TreeViewLabel(text=node['node_id'],
is_open=True), parent)
for child_node in node['children']:
populate_tree_view(tree_view, tree_node, child_node)
tree = []
rows = [(1, 'test1', 11), (2, 'test2', 2), (3, 'test3', 3), (4, 'test4', 4), (5, 'test5', 1)]
for r in rows:
tree.append({'node_id': r[1], 'children': []})
class TreeViewLabel(Label, TreeViewNode):
pass
class TreeviewGroup(Popup):
treeview = ObjectProperty(None)
tv = ObjectProperty(None)
#ti = ObjectProperty()
def __init__(self, **kwargs):
super(TreeviewGroup, self).__init__(**kwargs)
self.tv = TreeView(root_options=dict(text=""),
hide_root=False,
indent_level=4)
for branch in tree:
populate_tree_view(self.tv, None, branch)
self.remove_widgets()
self.treeview.add_widget(self.tv)
def remove_widgets(self):
for child in [child for child in self.treeview.children]:
self.treeview.remove_widget(child)
def select_node(self, node):
'''Select a node in the tree.
'''
if node.no_selection:
return
if self._selected_node:
self._selected_node.is_selected = False
node.is_selected = True
self._selected_node = node
print(node)
class GroupScreen(Screen):
groupName = ObjectProperty(None)
popup = ObjectProperty(None)
def display_groups(self, instance):
if len(instance.text) > 0:
if self.popup is None:
self.popup = TreeviewGroup()
#self.popup.filter(instance.text)
self.popup.open()
def select_node(self, node):
'''Select a node in the tree.
'''
if node.no_selection:
return
if self._selected_node:
self._selected_node.is_selected = False
node.is_selected = True
self._selected_node = node
print(node)
class Group(App):
#rows = [(1, 'test1', 111), (2, 'test2', 112), (3, 'test3', 113), (4, 'test4', 114)]
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
if __name__ == '__main__':
Group().run()
test.kv
#:kivy 1.10.0
<TreeViewLabel>:
on_touch_down:
app.root.stateName.text = self.text
app.root.popup.dismiss()
<TreeviewGroup>:
id: treeview
treeview: treeview
title: "Select City"
size_hint: None, None
size: 400, 400
auto_dismiss: False
BoxLayout
orientation: "vertical"
#TextInput:
#id: ti
#size_hint_y: .1
#on_text: root.filter(self.text)
BoxLayout:
id: treeview
#on_press: root.select_node(self.text)
Button:
size_hint: 1, 0.1
text: "Close"
on_release: root.dismiss()
<CustomLabel#Label>:
text_size: self.size
valign: "middle"
padding_x: 5
<SingleLineTextInput#TextInput>:
multiline: False
<GreenButton#Button>:
background_color: 1, 1, 1, 1
size_hint_y: None
height: self.parent.height * 0.150
GroupScreen:
stateName: stateName
GridLayout:
cols: 2
padding : 30,30
spacing: 10, 10
row_default_height: '40dp'
CustomLabel:
text: 'Name'
SingleLineTextInput:
id: stateName
on_text: root.display_groups(self)
CustomLabel:
text: 'Code'
CustomLabel:
text: '08'
GreenButton:
text: 'Ok'
#on_press: root.insert_data(stateName.text, cityName.text, shortName.text , pinCode.text)
GreenButton:
text: 'Cancel'
on_press: app.stop()
Label:
Label:
When i type anything in state name then a pop up open with treeview structure.
I want that when click on any node then it retrieve state code from database.And put value front of state code.at this time '08' is static value.database query is no issue for me but i dont know how to pass in a .py file after it put value in front of state code.And pop up should be close.
You can do this by adding a string property attribute to the Groupscreen class which will represent the statecode, then edit the select_node method to trigger the changes
...
from kivy.properties import ObjectProperty, StringProperty
...
class GroupScreen(Screen):
groupName = ObjectProperty(None)
popup = ObjectProperty(None)
statecode = StringProperty('08')
...
def select_node(self, node):
'''Select a node in the tree.
'''
for r in rows:
if node.text == r[1]:
self.statecode = str(r[2])
break
then in the kv:
<TreeViewLabel>:
on_touch_down:
app.root.stateName.text = self.text
app.root.select_node(self)
app.root.popup.dismiss()
...
GroupScreen:
stateName: stateName
GridLayout:
cols: 2
padding : 30,30
spacing: 10, 10
row_default_height: '40dp'
CustomLabel:
text: 'State Name'
SingleLineTextInput:
id: stateName
on_text: root.display_groups(self)
CustomLabel:
text: 'State Code'
CustomLabel:
text: root.statecode
...