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

Posted

技术标签:

【中文标题】如何使用 kv 文件刷新 Kivy 中的 GridLayout【英文标题】:How to refresh GridLayout in Kivy with kv file 【发布时间】:2021-08-29 10:28:54 【问题描述】:

我需要帮助。

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

我有两个屏幕:ScreenList 和 ScreenDetail。

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

ScreenList:包含项目列表

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

应用程序的工作原理:

    当我点击按钮 1 上的第一项时 我转到项目的详细信息。 我修改了第二个字段。我替换文本:Firt elementFirst and update data 录制后,我将应用程序重定向到包含 (ScreenList) 元素列表的屏幕。 但元素列表保持不变,然后数据库中的数据已被修改。 6.当我返回包含详细信息的屏幕(ScreenDetail)时,我看到数据已更新。

如何刷新 ScreenList 中的项目列表?

以图片为例

更新前列表

更新前

更新后

更新后列表

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

谢谢

【问题讨论】:

粘贴代码时,请确保它无需太多调整即可运行。在您的代码中,有一些不允许执行的数据库内容。请更新您的代码。 嗨。很抱歉这个疏忽。下次,我会考虑的。谢谢你。我会测试你的解决方案。 【参考方案1】:

一般来说,使用 Kivy 时需要注意的事项很少

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

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

针对您的问题的有效解决方案(仅显示已添加/更新的部分

创建自定义 GridLayout:

class MyGrid(GridLayout):
    pass

更新了ScreenList中的__init__方法:

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

【讨论】:

我修改了函数 go_to_detail_ (self, inst, btn) 以检索 id 以便选择项目的详细信息。在 kv 文件中,我也必须修改它: app.go_to_detail_(root,btn.text) 非常感谢,因为我已经尝试解决这个问题 1 个月了。感谢您的帮助和建议。现在效果很好。

以上是关于如何使用 kv 文件刷新 Kivy 中的 GridLayout的主要内容,如果未能解决你的问题,请参考以下文章

python中的kivy小部件到kv文件,如何控制它

Python / Kivy:.kv 文件中的条件设计

在 Kivy.kv 文件中,我如何引用另一个类中的方法

如何使用 .kv 文件在 kivy 中创建下拉列表

在 KV 语言中使用 Kivy Garden Graph

如何:main.py,带有 kivy 轮播代码的新类,kv 文件