如何使用kv文件刷新Kivy中的GridLayout

How to refresh GridLayout in Kivy with kv file

我需要帮助。

我用 Kivy 创建了一个小型移动应用程序。

我有两个屏幕:ScreenList 和 ScreenDetail。

但是包含 GridLayout 的屏幕 (ScreenList) 不会刷新

ScreenList:包含项目列表

ScreenDetail: 包含单个项目的详细信息。

应用程序的工作原理:

  1. 当我点击按钮 1 上的第一项时
  2. 我去项目的详细信息。
  3. 我修改了第二个字段。我将文本替换为:Firt elementFirst and update data
  4. 录制后,我将应用程序重定向到包含 (ScreenList) 元素列表的屏幕。
  5. 但是元素列表没有改变,那么数据库中的数据已经被修改了。 6.And 当我 return 到包含详细信息的屏幕 (ScreenDetail) 时,我看到数据已更新。

如何刷新屏幕列表中的项目列表?

以图片为例

更新前列表

更新前

更新后

更新后列表

这里是python代码:

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()

这里是kv代码:

#: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() 

谢谢

一般来说,在使用 Kivy 时需要做的笔记很少

  • 当您尝试在屏幕之间共享数据时,使用 app 方法而不是屏幕的特定方法通常很有用。

  • 并且当您需要创建大量按钮(可能在循环内)并在其事件上绑定方法时(on_presson_release),创建起来通常很糟糕按钮实例并在其事件上绑定方法,因为您需要做额外的工作以确保在触发事件时使用正确的参数调用这些绑定方法。而是创建一个自定义 class 模板并使用它。

您的问题的有效解决方案(仅显示 added/updated

已创建自定义 GridLayout:

class MyGrid(GridLayout):
    pass

已更新 __init__ 内的方法 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)

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'

这是更新后的 kv 代码:

#: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)