Search code examples
python-3.xkivykivy-language

How to add widgets to a label in scrollview Kivy


I'm trying to make a chat page which looks like a standard messaging app on a phone (Whatsapp, Imessage etc). To do this I have created a screen which contains ScrollView and have added a label widget to it.

To get the desired effect of the Whatsapp/Imessage look I think I then want a label widget to be added to the label on the ScrollView everytime the send button is pressed, this will then add the text of the text input box onto the screen.

Is it possible to add a label to another label? Every question I've looked at so far has been about adding a widget to a BoxLayout or GridLayout.

I'm also not sure on how I'll get the position of the label to change everytime the button is pressed but one step at a time!

kv file:

WindowManager:
    ChatPage:

<ChatPage>:
    name: "chat_page"
    layout_content: layout_content

    NavigationLayout:
        id: nav_layout
        MDNavigationDrawer:
            NavigationDrawerIconButton:
                text: "Test"

        FloatLayout:
            MDToolbar:
                pos_hint: {'top': 1}
                md_bg_color: 0.2, 0.6, 1, 1

            ScrollView:
                size_hint: 1, 0.6
                pos_hint: {"top" : 0.8, "bottom" : 0.5}
                GridLayout:
                    id: layout_content
                    cols: 1
                    size_hint_y: None
                    height: self.minimum_height
                    canvas:
                        Color:
                            rgba: (1, 1, 1, 1)
                        Rectangle:
                            size: self.size
                            pos: self.pos

                    Label:
                        text_size: self.width - 20, None
                        size_hint_y: None
                        height: self.texture_size[1]
                        color: 0,0,0,1

            BoxLayout:
                TextInput:
                    id: msg
                    hint_text: "Type your message here"
                    pos_hint: {"x": 0, "top": 0.15}
                    size_hint: 0.75, 0.15
                Button:
                    text: "Send"
                    background_normal: ""
                    background_color: 0, 0.6, 0, 1
                    pos_hint: {"x": 0.75, "top": 0.15}
                    size_hint: 0.25, 0.15
                    on_release: root.btn_press()

<SmoothLabel@Label>:
    background_color: 0,0,0,0
    background_normal: ""
    back_color: 1,0,1,1
    border_radius: [6]
    canvas.before:
        Color:
            rgba: 0.2,0.6,1,1 #This changes the label colour
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: self.border_radius

py file:

import kivy
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.window import Window
from kivymd.theming import ThemeManager
from kivy.uix.scrollview import ScrollView

Window.clearcolor = (1,1,1,1)

class SmoothLabel(Label):
    pass

class WindowManager(ScreenManager):
    pass

class ChatPage(Screen):
    layout_content = ObjectProperty(None)
    def btn_press(self):
        if self.ids.msg.text:
            self.layout_content.add_widget(SmoothLabel(text=self.ids.msg.text, size_hint_x=0.5, size_hint_y=0.1, pos_hint={"x": 0.1, "top": 0.8}, background_color=(0.2, 0.6, 1, 1)))
            self.ids.msg.text = ""
        else:
            pass

class MyApp(App):
    theme_cls = ThemeManager()

    def build(self):
        kv = Builder.load_file("kivy.kv")
        sm = WindowManager()

        screens = [ChatPage(name="chat_page")]
        for screen in screens:
            sm.add_widget(screen)

        sm.current = "chat_page"
        return sm


if __name__ == '__main__':
    MyApp().run()

Thanks


Solution

  • Made a few changes to your code (in addition to removing all the kivyMD) to get it to work:

    First, I changed the SmoothLabel rule in your kv to:

    <SmoothLabel>:
        size_hint: None, None
        size: self.texture_size
        background_color: 0,0,0,0
        background_normal: ""
        back_color: 1,0,1,1
        border_radius: [6]
        canvas.before:
            Color:
                rgba: 0.2,0.6,1,1 #This changes the label colour
            RoundedRectangle:
                size: self.size
                pos: self.pos
                radius: self.border_radius
    

    Took out the @Label since that is already specified in your python code, and added the size_hint and size (otherwise, the GridLayout decides the size of the SmoothLabel children).

    Also, removed the

    background_color=(0.2, 0.6, 1, 1)
    

    from the SmoothLabel creation (that was throwing an exception for me), so the ChatPage definition now looks like:

    class ChatPage(Screen):
        layout_content = ObjectProperty(None)
        def btn_press(self):
            if self.ids.msg.text:
                self.layout_content.add_widget(SmoothLabel(text=self.ids.msg.text))
                self.ids.msg.text = ""
            else:
                pass
    

    The Label widget has no background_color attribute. And, since I added size_hint to the rule, I removed it from the SmoothLabel() call. Also, the GridLayout does not support pos_hint.

    That was enough to get the code working for me.