Related
I'm using Kivy to make a graphical interface to my password manager.
I already make the login page. I have no idea how to upload my password login nto my other class in a different file to decrypt my other password ?
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file('libs\kv\login_page.kv')
def logger(self):
try :
passwd = verif_password(self.root.ids.password.text)
passwd_bdd = passwd
if passwd == True :
self.get_running_app().stop()
import graphical_password
else :
print("NO")
except :
print("No passs")
MainApp().run()
My Import graphical_password is this code :
class MainApp(MDApp):
def build(self):
screen = Screen()
table = MDDataTable(
pos_hint = {'center_x' : 0.5, 'center_y' : 0.5},
size_hint = (0.9, 0.6),
check = True,
column_data =[
("F_name", dp(30)),
("Name", dp(30)),
("Mail", dp(30)),
("Phone", dp(30)),
],
row_data = [
("P1","P2","GAMIL","0658"),
("P3","P4","GAMIL","0658"),
]
)
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "BlueGray"
screen.add_widget(table)
return screen
MainApp().run()
Do you know how can I get the password input in my first page into my other?
Use:
main.py
from kivymd.app import MDApp
from graphical_password import Screen_jbsidis
from graphical_password import *
from kivy.lang import Builder
from kivy.clock import Clock
def verif_password(a): return True
class MainAppjbsidis(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.passs=""
self.user=""
self.mainx_jbsidis=Builder.load_file('libs/kv/login_page.kv')
def build(self):
global passs
global user
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
return self.mainx_jbsidis
def logger(self,user,pasword_jbsidis):
try:
print(user.text,pasword_jbsidis.text)
self.passs=pasword_jbsidis.text
self.user=user.text
passwd = verif_password(pasword_jbsidis.text)
passwd_bdd = passwd
if passwd == True :
jbsidis="self.get_running_app().stop() #this is an issue because this may kill the thread and not execute the next one, plus it may use additional unnecessary memory"
jbsidis5="import graphical_password "
jbsidis6="self.mainx_jbsidis.ids.jbsidisBody.add_widget(Screen_jbsidis())"
self.mainx_jbsidis.ids.jbsidisBody.current="dos"
else :
print("NO")
except Exception as e:
print("No passs",str(e))
def put_data(self,TABLE):
kar="""
TABLE.data=[]
new_datax=[
{'text': self.passs, 'Index': 'P1', 'range': [0, 3], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': self.user, 'Index': 'P1', 'range': [0, 3], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': 'jbsidis', 'Index': 'P1', 'range': [0, 3], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': '8822', 'Index': 'P1', 'range': [0, 3], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': 'MyOtherPassword', 'Index': 'P3', 'range': [4, 7], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': 'MyNameA', 'Index': 'P3', 'range': [4, 7], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': 'jbsidis555', 'Index': 'P3', 'range': [4, 7], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData},
{'text': '2222', 'Index': 'P3', 'range': [4, 7], 'selectable': True, 'viewclass': 'CellRow', 'table': TableData}
]
TABLE.data.append(new_datax)
TABLE.table_data.recycle_data=[]
row_dataZ = [
(self.passs,self.user,"jbsidis","1111"),
("AnotherPASS","OtherUser","jbsidis767","23232"),
]
TABLE.table_data=TableData(
TABLE.header,
row_data=row_dataZ,
check=True,
rows_num=2,
_parent=TABLE,
)
"""
self.mainx_jbsidis.ids.TABLE_EXTRA_jbsidis.clear_widgets()
self.table_refresher_jbsidis()
def table_refresher_jbsidis(self):
self.tablejbsidis = MDDataTable(
pos_hint = {'center_x' : 0.5, 'center_y' : 0.5},
size_hint = (0.9, 0.6),
check = True,
column_data =[
("Password", dp(30)),
("User", dp(30)),
("Mail", dp(30)),
("Phone", dp(30)),
],
row_data = [
(self.passs,self.user,"jbsidis","062328"),
("Otherpass","OtherUser","jbsidis222","2222"),
]
)
self.mainx_jbsidis.ids.TABLE_EXTRA_jbsidis.add_widget(self.tablejbsidis)
def constant_checker(self):
if self.passs!="" and self.user!="":
T=self.mainx_jbsidis.ids.TABLE_EXTRA_jbsidis.children
jbsidis223="print(T)"
jbsidis55333="[<graphical_password.MDDataTable object at 0x7f5a5dfe8740>]"
new_data= [
(self.passs,self.user,"jbsidis","06655")
,(self.passs,self.user,"jbsidis2","06655")]
Clock.schedule_once(lambda x:self.put_data(T[0]),3)
MainAppjbsidis().run()
libs/kv/login_page.kv
#:import Screen_jbsidis graphical_password.Screen_jbsidis
Screen:
ScreenManager:
id: jbsidisBody
Screen:
name: "uno_jbsidis"
FloatLayout:
BoxLayout:
orientation: "vertical"
padding: dp(30)
BoxLayout:
BoxLayout:
MDTextField:
id: jbsidis1
pos_hint: {"center_x": .5, "center_y": .5}
hint_text: "User"
MDTextField:
id: jbsidis2
pos_hint: {"center_x": .5, "center_y": .5}
hint_text: "Password"
MDTextButton:
id: jbsidis3
pos_hint: {"center_x": .5, "center_y": .5}
text: "Forgot password?"
MDFillRoundFlatButton:
id: jbsidis4
pos_hint: {"center_x": .5, "center_y": .5}
text: "Login"
on_release:
app.logger(root.ids.jbsidis1,root.ids.jbsidis2)
app.constant_checker()
BoxLayout:
BoxLayout:
Screen_jbsidis:
id: TABLE_EXTRA_jbsidis
name: "dos"
graphical_password.py
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivy import Logger
from kivy.metrics import dp
from kivy.properties import (
BooleanProperty,
ListProperty,
ObjectProperty,
NumericProperty,
DictProperty,
StringProperty,
OptionProperty,
)
from kivy.clock import Clock
from kivy.uix.scrollview import ScrollView
from kivy.uix.behaviors import FocusBehavior, ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import HoverBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.dialog import BaseDialog
from kivymd.uix.tooltip import MDTooltip
from kivymd.uix.menu import MDDropdownMenu
Builder.load_string(
"""
#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE
<CellRow>
orientation: "vertical"
canvas.before:
Color:
rgba:
(root.theme_cls.bg_darkest if root.theme_cls.theme_style == "Light" else root.theme_cls.bg_light) \
if self.selected else root.theme_cls.bg_normal
Rectangle:
pos: self.pos
size: self.size
on_press: if DEVICE_TYPE != "desktop": root.table.on_mouse_select(self)
on_enter: if DEVICE_TYPE == "desktop": root.table.on_mouse_select(self)
MDBoxLayout:
id: box
padding: "8dp", "8dp", 0, "8dp"
spacing: "16dp"
MDCheckbox:
id: check
size_hint: None, None
size: 0, 0
opacity: 0
on_active: root.select_check(self.active)
MDLabel:
id: label
text: " " + root.text
color: (1, 1, 1, 1) if root.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
<CellHeader>
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
spacing: "4dp"
tooltip_text: root.text
MDLabel:
text: " " + root.text
size_hint_y: None
height: self.texture_size[1]
bold: True
color: (1, 1, 1, 1) if root.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
MDSeparator:
id: separator
<TableHeader>
bar_width: 0
do_scroll: False
size_hint: 1, None
height: header.height
MDGridLayout:
id: header
rows: 1
cols_minimum: root.cols_minimum
adaptive_size: True
padding: 0, "8dp", 0, 0
MDBoxLayout:
orientation: "vertical"
MDBoxLayout:
id: box
padding: "8dp", "8dp", "4dp", 0
spacing: "16dp"
MDCheckbox:
id: check
size_hint: None, None
size: 0, 0
opacity: 0
on_active: root.table_data.select_all(self.state)
disabled: True
CellHeader:
id: first_cell
MDSeparator:
<TableData>
data: root.recycle_data
data_first_cells: root.data_first_cells
key_viewclass: "viewclass"
TableRecycleGridLayout:
id: row_controller
key_selection: "selectable"
cols: root.total_col_headings
cols_minimum: root.cols_minimum
default_size: None, dp(52)
default_size_hint: 1, None
size_hint: None, None
height: self.minimum_height
width: self.minimum_width
orientation: 'lr-tb'
multiselect: True
touch_multiselect: True
<TablePagination>
adaptive_height: True
spacing: "8dp"
Widget:
MDLabel:
text: "Rows per page"
size_hint: None, 1
width: self.texture_size[0]
text_size: None, None
font_style: "Caption"
color: (1, 1, 1, 1) if root.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
MDDropDownItem:
id: drop_item
pos_hint: {'center_y': .5}
text: str(root.table_data.rows_num)
font_size: "14sp"
on_release: root.table_data.open_pagination_menu()
Widget:
size_hint_x: None
width: "32dp"
MDLabel:
id: label_rows_per_page
text: f"1-{root.table_data.rows_num} of {len(root.table_data.row_data)}"
size_hint: None, 1
#width: self.texture_size[0]
text_size: None, None
font_style: "Caption"
color: (1, 1, 1, 1) if root.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
MDIconButton:
id: button_back
icon: "chevron-left"
user_font_size: "20sp"
pos_hint: {'center_y': .5}
disabled: True
on_release: root.table_data.set_next_row_data_parts("back")
MDIconButton:
id: button_forward
icon: "chevron-right"
user_font_size: "20sp"
pos_hint: {'center_y': .5}
on_release: root.table_data.set_next_row_data_parts("forward")
<MDDataTable>
MDCard:
id: container
orientation: "vertical"
elevation: 14
md_bg_color: 0, 0, 0, 0
padding: "24dp", "24dp", "8dp", "8dp"
canvas:
Color:
rgba: root.theme_cls.bg_normal
RoundedRectangle:
pos: self.pos
size: self.size
""")
class TableRecycleGridLayout(
FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout
):
selected_row = NumericProperty(0)
table_data = ObjectProperty(None)
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:
self.selected_row = 0
self.select_row(nodes)
return None, None
if len(nodes) == 1:
return None, None
index = selected[-1]
if index > len(nodes):
last = len(nodes)
else:
last = nodes.index(index)
self.clear_selection()
return last, nodes
def select_next(self, instance):
"""Select next row."""
self.table_data = instance
last, nodes = self.get_nodes()
if not nodes:
return
if last == len(nodes) - 1:
self.selected_row = nodes[0]
else:
self.selected_row = nodes[last + 1]
self.selected_row += self.table_data.total_col_headings
self.select_row(nodes)
def select_current(self, instance):
self.table_data = instance
last, nodes = self.get_nodes()
if not nodes:
return
self.select_row(nodes)
def select_row(self, nodes):
col = self.table_data.recycle_data[self.selected_row]["range"]
for x in range(col[0], col[1] + 1):
self.select_node(nodes[x])
class CellRow(
ThemableBehavior,
RecycleDataViewBehavior,
HoverBehavior,
ButtonBehavior,
BoxLayout,
):
text = StringProperty()
table = ObjectProperty()
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def on_table(self, instance, table):
if not table.check:
self.ids.box.padding = 0
self.ids.box.spacing = 0
def refresh_view_attrs(self, table_data, index, data):
self.index = index
return super().refresh_view_attrs(table_data, index, data)
def on_touch_down(self, touch):
if super().on_touch_down(touch):
if self.table._parent:
self.table._parent.dispatch("on_row_press", self)
return True
def apply_selection(self, table_data, index, is_selected):
self.selected = is_selected
if table_data.check:
if self.text in table_data.data_first_cells:
self.ids.check.size = (dp(32), dp(32))
self.ids.check.opacity = 1
self.ids.box.spacing = dp(16)
self.ids.box.padding[0] = dp(8)
else:
self.ids.check.size = (0, 0)
self.ids.check.opacity = 0
self.ids.box.spacing = 0
self.ids.box.padding[0] = 0
if table_data._rows_number in table_data.current_selection_check:
for index in table_data.current_selection_check[
table_data._rows_number
]:
if (
self.index
in table_data.current_selection_check[
table_data._rows_number
]
):
self.ids.check.state = "down"
else:
self.ids.check.state = "normal"
else:
self.ids.check.state = "normal"
def select_check(self, active):
if active and self.index not in self.table.current_selection_check:
if (
not self.table._rows_number
in self.table.current_selection_check
):
self.table.current_selection_check[self.table._rows_number] = []
if (
self.index
not in self.table.current_selection_check[
self.table._rows_number
]
):
self.table.current_selection_check[
self.table._rows_number
].append(self.index)
else:
if self.table._rows_number in self.table.current_selection_check:
if (
self.index
in self.table.current_selection_check[
self.table._rows_number
]
and not active
):
self.table.current_selection_check[
self.table._rows_number
].remove(self.index)
self.table.get_select_row(self.index)
class CellHeader(MDTooltip, BoxLayout):
text = StringProperty()
class TableHeader(ScrollView):
table_data = ObjectProperty()
column_data = ListProperty()
col_headings = ListProperty()
sort = BooleanProperty(False)
cols_minimum = DictProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
for i, col_heading in enumerate(self.column_data):
self.cols_minimum[i] = col_heading[1] * 5
self.col_headings.append(col_heading[0])
if i:
self.ids.header.add_widget(
CellHeader(text=col_heading[0], width=self.cols_minimum[i])
)
else:
self.ids.first_cell.text = col_heading[0]
self.ids.first_cell.ids.separator.height = 0
self.ids.first_cell.width = self.cols_minimum[i]
def on_table_data(self, instance, value):
if self.table_data.check:
self.ids.check.size = (dp(32), dp(32))
self.ids.check.opacity = 1
else:
self.ids.box.padding[0] = 0
self.ids.box.spacing = 0
def on_sort(self, instance, value):
Logger.info("TableData: Sorting table items is not implemented")
class TableData(RecycleView):
recycle_data = ListProperty()
data_first_cells = ListProperty()
row_data = ListProperty()
total_col_headings = NumericProperty(0)
cols_minimum = DictProperty()
table_header = ObjectProperty()
pagination_menu = ObjectProperty()
pagination = ObjectProperty()
check = ObjectProperty()
rows_num = NumericProperty()
pagination_menu_open = BooleanProperty(False)
current_selection_check = DictProperty()
sort = BooleanProperty()
_parent = ObjectProperty()
_rows_number = NumericProperty(0)
_rows_num = NumericProperty()
_current_value = NumericProperty(1)
_to_value = NumericProperty()
_row_data_parts = ListProperty()
def __init__(self, table_header, **kwargs):
super().__init__(**kwargs)
self.table_header = table_header
self.total_col_headings = len(table_header.col_headings)
self.cols_minimum = table_header.cols_minimum
self.set_row_data()
Clock.schedule_once(self.set_default_first_row, 0)
def get_select_row(self, index):
row = []
for data in self.recycle_data:
if index in data["range"]:
row.append(data["text"])
self._parent.dispatch("on_check_press", row)
def set_default_first_row(self, dt):
self.ids.row_controller.select_next(self)
def sort_by_name(self):
print(1)
def set_row_data(self):
data = []
low = 0
high = self.total_col_headings - 1
self.recycle_data = []
self.data_first_cells = []
if self._row_data_parts:
for row in self._row_data_parts[self._rows_number]:
for i in range(len(row)):
data.append([row[i], row[0], [low, high]])
low += self.total_col_headings
high += self.total_col_headings
for j, x in enumerate(data):
if x[0] == x[1]:
self.data_first_cells.append(x[0])
self.recycle_data.append({"text": str(x[0]),"Index": str(x[1]),"range": x[2],"selectable": True,"viewclass": "CellRow","table": self})
if not self.table_header.column_data:
raise ValueError(f"Set value for column_data in class TableData")
self.data_first_cells.append(self.table_header.column_data[0][0])
def set_text_from_of(self, direction):
if self.pagination:
if direction == "forward":
if (len(self._row_data_parts[self._rows_number])< self._to_value):
self._current_value = self._current_value + self.rows_num
else:
self._current_value = self._current_value + len(self._row_data_parts[self._rows_number])
self._to_value = self._to_value + len(self._row_data_parts[self._rows_number])
if direction == "back":
self._current_value = self._current_value - len(self._row_data_parts[self._rows_number])
self._to_value = self._to_value - len(self._row_data_parts[self._rows_number])
if direction == "increment":
self._current_value = 1
self._to_value = self.rows_num + self._current_value - 1
self.pagination.ids.label_rows_per_page.text = f"{self._current_value}-{self._to_value} of {len(self.row_data)}"
def select_all(self, state):
for i, data in enumerate(self.recycle_data):
opts = self.layout_manager.view_opts
cell_row_obj = self.view_adapter.get_view(i, self.data[i], opts[i]["viewclass"])
cell_row_obj.ids.check.state = state
self.on_mouse_select(cell_row_obj)
cell_row_obj.select_check(True if state == "down" else False)
def close_pagination_menu(self, *args):
self.pagination_menu_open = False
def open_pagination_menu(self):
if self.pagination_menu.items:
self.pagination_menu_open = True
self.pagination_menu.open()
def set_number_displayed_lines(self, instance_menu_item):
self.rows_num = int(instance_menu_item.text)
self.set_row_data()
self.set_text_from_of("increment")
def set_next_row_data_parts(self, direction):
if direction == "forward":
self._rows_number += 1
self.pagination.ids.button_back.disabled = False
elif direction == "back":
self._rows_number -= 1
self.pagination.ids.button_forward.disabled = False
self.set_row_data()
self.set_text_from_of(direction)
if self._to_value == len(self.row_data):
self.pagination.ids.button_forward.disabled = True
if self._current_value == 1:
self.pagination.ids.button_back.disabled = True
def _split_list_into_equal_parts(self, lst, parts):
for i in range(0, len(lst), parts):
yield lst[i : i + parts]
def on_mouse_select(self, instance):
if not self.pagination_menu_open:
if self.ids.row_controller.selected_row != instance.index:
self.ids.row_controller.selected_row = instance.index
self.ids.row_controller.select_current(self)
def on_rows_num(self, instance, value):
if not self._to_value:
self._to_value = value
self._rows_number = 0
self._row_data_parts = list(
self._split_list_into_equal_parts(self.row_data, value)
)
class TablePagination(ThemableBehavior, MDBoxLayout):
table_data = ObjectProperty()
class MDDataTable(BaseDialog):
column_data = ListProperty()
row_data = ListProperty()
sort = BooleanProperty(False)
check = BooleanProperty(False)
use_pagination = BooleanProperty(False)
rows_num = NumericProperty(5)
pagination_menu_pos = OptionProperty("center", options=["center", "auto"])
pagination_menu_height = NumericProperty("140dp")
background_color = ListProperty([0, 0, 0, 0])
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.register_event_type("on_row_press")
self.register_event_type("on_check_press")
self.header = TableHeader(column_data=self.column_data, sort=self.sort)
self.table_data = TableData(
self.header,
row_data=self.row_data,
check=self.check,
rows_num=self.rows_num,
_parent=self,
)
self.pagination = TablePagination(table_data=self.table_data)
self.table_data.pagination = self.pagination
self.header.table_data = self.table_data
self.table_data.fbind("scroll_x", self._scroll_with_header)
self.ids.container.add_widget(self.header)
self.ids.container.add_widget(self.table_data)
if self.use_pagination:
self.ids.container.add_widget(self.pagination)
Clock.schedule_once(self.create_pagination_menu, 0.5)
def on_row_press(self, *args):
"""Called when a table row is clicked."""
def on_check_press(self, *args):
"""Called when the check box in the table row is checked."""
def _scroll_with_header(self, instance, value):
self.header.scroll_x = value
def create_pagination_menu(self, interval):
menu_items = [
{"text": f"{i}"}
for i in range(
self.rows_num, len(self.row_data) // 2, self.rows_num,
)
]
pagination_menu = MDDropdownMenu(
caller=self.pagination.ids.drop_item,
items=menu_items,
use_icon_item=False,
position=self.pagination_menu_pos,
max_height=self.pagination_menu_height,
callback=self.table_data.set_number_displayed_lines,
width_mult=2,
)
pagination_menu.bind(on_dismiss=self.table_data.close_pagination_menu)
self.table_data.pagination_menu = pagination_menu
from kivy.metrics import dp
class Screen_jbsidis(Screen):
def __init__(self, **kwargs):
super(Screen_jbsidis, self).__init__(**kwargs)
ii="screen = Screen()"
self.table = MDDataTable(
pos_hint = {'center_x' : 0.5, 'center_y' : 0.5},
size_hint = (0.9, 0.6),
check = True,
column_data =[
("F_name", dp(30)),
("Name", dp(30)),
("Mail", dp(30)),
("Phone", dp(30)),
],
row_data = [
("P1","P2","GAMIL","0658"),
("P3","P4","GAMIL","0658"),
]
)
self.add_widget(self.table)
#return Screen_jbsidis
m="MainApp().run()"
Video showing how it works: https://youtu.be/84wpXlCaTDM
Pics, jbsidis:
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
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
...
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
...