I need help.
I created a small mobile application with Kivy.
I have two screens: ScreenList and ScreenDetail.
However the screen(ScreenList) containing GridLayout does not refresh
ScreenList: contains a list of items
ScreenDetail: Contains the details of a single item.
How the app works:
Firt element
for First and update data
How can I refresh the item list in ScreenList?
Here are the pictures as an example
List before update
before update
after update
List after update
Here is the python code:
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.properties import ObjectProperty, StringProperty
from kivy.lang import Builder
from kivymd.uix.picker import MDTimePicker
from kivymd.uix.picker import MDDatePicker
from kivymd.app import MDApp
import sqlite3
import os.path
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
db_path = os.path.join(BASE_DIR, "donnee/ProjetMaison.db")
def donnee_dic(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
cur_id = None
class ScreenList(Screen):
data_grid = ObjectProperty()
def go_to_detail(self, instance):
global cur_id
cur_id = int(instance.text)
self.manager.current = 'screen_detail'
def __init__(self, **kwargs):
super(ScreenList, self).__init__(**kwargs)
con_list_course = sqlite3.connect(db_path)
con_list_course.row_factory = donnee_dic
curss_list_course = con_list_course.cursor()
data_list_course = curss_list_course.execute("select * FROM courses")
self.data_grid.bind(minimum_height=self.data_grid.setter('height'))
for row in data_list_course:
template_screen = GridLayout(cols=2, size_hint_y=None, height=40)
template_screen.add_widget(Label(text=row['nom']))
template_screen.add_widget(Button(text=str(row['id']), on_press=self.go_to_detail))
self.data_grid.add_widget(template_screen)
con_list_course.close()
def Maj_colonne(id, nom):
try:
sqliteConnection = sqlite3.connect(db_path)
cursor = sqliteConnection.cursor()
sqlite_update_query = """Update courses set nom = ? where id = ?"""
columnValues = (nom, id)
cursor.execute(sqlite_update_query, columnValues)
sqliteConnection.commit()
sqliteConnection.commit()
cursor.close()
except sqlite3.Error as error:
print("Erreur de connexion", error)
finally:
if sqliteConnection:
sqliteConnection.close()
class ScreenDetail(Screen):
label_id = ObjectProperty()
label_nom = ObjectProperty()
def __init__(self, **kwargs):
super(ScreenDetail, self).__init__(**kwargs)
def on_enter(self):
global cur_id
conn = sqlite3.connect(db_path)
cursor = conn.execute("select * FROM courses where id=?",str(cur_id))
for row in cursor:
self.label_id.text = str(row[0])
self.label_nom.text = str(row[1])
cursor.close()
def update_course(self):
id_pk = self.ids['label_id'].text
nom = self.ids['label_nom'].text
if id_pk:
Maj_colonne(str(id_pk), str(nom))
self.ids['label_id'].text = ''
self.ids['label_nom'].text = ''
self.manager.current = 'screen_list'
class Listapp(MDApp):
def build(self):
screenmanager = ScreenManager()
screenmanager.add_widget(ScreenList(name='screen_list'))
screenmanager.add_widget(ScreenDetail(name='screen_detail'))
return screenmanager
if __name__ == '__main__':
Listapp().run()
Here is the kv code:
#:import utils kivy.utils
<ScreenList>:
data_grid: data_grid
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.primary_color
radius: [25, 0, 0, 0]
ScrollView:
MDGridLayout:
id: data_grid
cols: 1
spacing:10
size_hint_y:None
<ScreenDetail>:
label_id: label_id
label_nom: label_nom
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.primary_color
ScrollView:
GridLayout:
id: detail_grid
cols:2
Label:
text: 'Numéro:'
bold: True
TextInput:
id: label_id
text: ''
Label:
text: 'Nom:'
bold: True
TextInput:
id: label_nom
text: ''
Button:
text: 'OK'
size_hint_y: None
on_press: root.update_course()
Thank you
When you're trying to share data in between screens, it's often useful to use app
methods instead of specific methods of screens.
And when you need to create lots of buttons, maybe inside a loop, and bind methods on its events( on_press
, on_release
), it's often bad to create button instances on the fly and bind methods on its events because you'll need to do extra work to make sure that those bound methods are called with right parameters when events are fired. Rather create a custom class template and use that instead.
Created custom GridLayout:
class MyGrid(GridLayout):
pass
Updated __init__
method inside ScreenList
:
def __init__(self, **kwargs):
#...
app = MDApp.get_running_app()
for row in data_list_course:
template_screen = MyGrid()
template_screen.ids.lbl.text = row['nom']
template_screen.ids.btn.text = str(row['id'])
self.data_grid.add_widget(template_screen)
Added methods inside app
class:
class Listapp(MDApp):
def build(self):
self.screenmanager = ScreenManager()
self.screenmanager.add_widget(ScreenList(name='screen_list'))
self.screenmanager.add_widget(ScreenDetail(name='screen_detail'))
return self.screenmanager
def go_to_detail_(self, inst):
self.inst = inst
self.screenmanager.current = 'screen_detail'
def update_course_(self, label_id, label_nom):
c = self.inst.children[::-1]
c[0].text = label_nom.text
c[1].text = label_id.text
print(label_id.text, label_nom.text)
if label_id.text:
Maj_colonne(str(id_pk), str(nom))
label_nom.text = ''
label_id.text = ''
self.screenmanager.current = 'screen_list'
Here's the updated kv code:
#:import utils kivy.utils
<ScreenList>:
data_grid: data_grid
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.primary_color
radius: [25, 0, 0, 0]
ScrollView:
MDGridLayout:
id: data_grid
cols: 1
spacing:10
size_hint_y:None
<ScreenDetail>:
label_id: label_id
label_nom: label_nom
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.primary_color
ScrollView:
GridLayout:
id: detail_grid
cols:2
Label:
text: 'Numéro:'
bold: True
TextInput:
id: label_id
text: ''
Label:
text: 'Nom:'
bold: True
TextInput:
id: label_nom
text: ''
Button:
text: 'OK'
size_hint_y: None
on_press: app.update_course_(label_id, label_nom)
<MyGrid>:
cols:2
size_hint_y:None
height:40
Label:
id: lbl
text: ''
Button:
id: btn
text: ''
on_press:
app.go_to_detail_(root)