Search code examples
pythonlayoutkivywidget

Python Kivy self.add_widget() doesn't update while code running


The idea is to create a texting app that works like Messenger. I am having a problem with the chat history which is a "BoxLayer (or GridLayer)" containing all previous text. I want when I insert a new text, it's will appear as a new label or a box and stay below the previous text like this, but when I run the code and insert input text, it's not appearing. I spent hours to find the answer both myself and on the internet, but it's kind of hard for a beginner like me.

enter image description here

.Py file

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.image import Image
from kivy.properties import StringProperty
from kivy.core.window import Window
from kivy.graphics.context_instructions import Color

class MainWidget(Widget):
    request = StringProperty("This is a previous text, don't mind")
    insert_text = StringProperty("Insert Here")
    window_size = (305,400)
    refresh_key = False
    
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.Window_Minimum()
    
    def on_size(self,*args):
        print(self.width,self.height)
    
    def on_text_validate(self,widget): #<<<<<<<<<<<<<<<<<<<<<<<<<<< input text
        request=widget.text
        Chat_history_update().chat_history(request)
        
    def Window_Minimum(self):
        Window.minimum_width,Window.minimum_height=self.window_size

class Chat_history_update(BoxLayout):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        l = Label(text="This is a previous text, don't mind",size_hint=(1, None),height=("30dp"))
        self.add_widget(l)
        
    def chat_history(self,request): # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Add Label Function
        l = Label(text=request, size_hint=(1, None),height=("30dp"))
        self.add_widget(l) # <<<<<<<<<<<<< This won't update my app screen

class Assistant(App):
    pass

if __name__ == "__main__":
    Assistant().run()

Kv file

MainWidget:

<MainWidget>:
    BoxLayout:
        size: root.size
        orientation: "vertical"
        GridLayout:
            cols: 3
            size_hint: 1,None
            height: "50dp"
            spacing: "10dp"
            padding: "10dp"
            Label:
                text:"Erza Assistant"
            Button:
                text:"Edit Path"
            Button:
                text:"Setting"
        GridLayout:
            size: self.size
            rows: 2
            spacing: "10dp"
            padding: "10dp"
            ScrollView: #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Here my text display
                Chat_history_update:
                    orientation: "vertical"
                    size_hint: 1, None
                    height: self.minimum_height

            TextInput:
                size_hint: 1, None
                height: "40dp"
                text: root.insert_text
                multiline: False
                on_text_validate: root.on_text_validate(self)

Solution

  • Your code:

    Chat_history_update().chat_history(request)
    

    is creating a new instance of Chat_history_update, and calling chat_history() for that new instance. That new instance is not part of your GUI, so you will see no effect. The fix is to access the correct instance of Chat_history_update (the one that is in your GUI). To do that, you can add an id in your kv:

            ScrollView: #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Here my text display
                Chat_history_update:
                    id: chu
                    orientation: "vertical"
                    size_hint: 1, None
                    height: self.minimum_height
    

    And then use that id in your py code:

    def on_text_validate(self,widget): #<<<<<<<<<<<<<<<<<<<<<<<<<<< input text
        request=widget.text
        self.ids.chu.chat_history(request)