Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kivy self sizing TextInput (multiline)

Tags:

python

kivy

Good evening!

I am trying to make a TextInput widget increase in height when the text goes on the next line. The thing is, this is inside an image and it has to scale as well. Here is what I'm talking about:

On a side note, everytime I type a certain text, the space goes on the next line like this:

The quick brown fox jumped over   |
the lazy dog.  The quick brown fox|
 jumped over the lazy dog.  The   |
sly brown fox jumped over the lazy|

Is there a way to avoid this?

Here is the part of the file.kv file with the problem:

#:kivy 1.10.0

<Manager>:
    Chat:
        name: 'chat'
<Chat>:
    canvas:
        Rectangle:
            pos: self.x, 0
            size: self.width, self.height

    Button:
        id: stgs
        background_down: './icons/settings-press.png'
        background_normal: './icons/settings.png'
        border: 0, 0, 0, 0
        always_release: True
        right: root.right - 20
        top: root.top - 10
        size: 40, 40
        size_hint: None, None
        on_release:
            root.manager.transition.direction = 'down'
            root.manager.current = 'settings'

    Button:
        id: bck
        background_down: './icons/back-press.png'
        background_normal: './icons/back.png'
        border: 0, 0, 0, 0
        x: root.x + 20
        top: root.top - 10
        size: 40, 40
        size_hint: None, None
        on_release:
            root.manager.transition.direction = 'right'
            root.manager.current = 'main'

    BoxLayout:
        orientation: 'horizontal'
        padding: 10, 10, 10, 10
        cols: 2
        Image:
            id: inpimg
            source: './icons/user_inp.png'
            x: root.x + 10
            y: root.y + 10
            size: root.width - 40, 40
            size_hint: 0.9, None
            allow_stretch: True
            keep_ratio: False
            TextInput:
                id: usrinp
                valign: 'middle'
                halign: 'left'
                font_size: 16
                multiline: True
                x: root.ids['inpimg'].x + 10
                y: root.ids['inpimg'].y + 5
                background_color: 0, 0, 0, 0
                size: root.width - 80, 33

        Button:
            id: post
            foreground_color: 0, 0, 0, 0
            background_down: './icons/type1-press.png'
            background_normal: './icons/type1.png'
            border: 0, 0, 0, 0
            size: 40, 40
            x: root.width * 14/17 + 5
            y: root.y + 20
            size_hint: None, None

Here is the minimal .py file:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen


class Chat(Screen):
    pass

class Manager(ScreenManager):
    pass

class FileApp(App):
    def build(self):
        return Manager()


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

If you know a better way of putting a text box inside an image, please let me know! This method that I thought of seems kinda forced...

Optional question: Is it possible to use '.gmd' files with kivy?

Thank you in advance!

like image 856
Takusui Avatar asked Oct 16 '25 08:10

Takusui


2 Answers

Simple example code with a multiline TextInput whose height is dynamically modified according to its text content:

textinputtextsize.kv file

<TextInputTextSize>:
    canvas.before:
        Color:
            rgb: [0.22,0.22,0.22]
        Rectangle:
            pos: self.pos
            size: self.size
    orientation: "vertical"
    textInputSingleLine: txt_input_singleline
    textInputMultiline: txt_input_multiline

    GridLayout:
        cols: 1
        canvas.before:
            Rectangle:
                pos: self.pos
                size: self.size
        TextInput:
            id: txt_input_singleline
            size_hint_y: None
            height: "28dp"
            focus: True
            multiline: False
            on_text_validate: root.submitRequest() # ENTER triggers root.submitRequest()
        TextInput:
            id: txt_input_multiline
            text: "Audio - ET L'UNIVERS DISPARAÎTRA La nature   \nillusoire de notre réalité et le pouvoir \ntranscendant du véritable pardon \n+ commentaires de Gary Renard"
            size_hint_y: None
            height: (len(txt_input_multiline._lines)+1) * txt_input_multiline.line_height

py file

from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout


class TextInputTextSize(BoxLayout):
    textInput = ObjectProperty()
    textInputMultiline = ObjectProperty()

    def submitRequest(self):
        # Get the request from the TextInput
        textInputTxt = self.textInputSingleLine.text
        self.textInputMultiline.text += '\n' + textInputTxt

class TextInputTextSizeApp(App):
    def build(self):
        return TextInputTextSize()

if __name__ == '__main__':
    TextInputTextSizeApp().run()
like image 67
Jean-Pierre Schnyder Avatar answered Oct 17 '25 20:10

Jean-Pierre Schnyder


Ok, I found something. This doesn't seem to be the best way to do it as the text inside cannot be clicked anymore but if you find a work around this, please let me know! Ok, back to the solution:

BoxLayout:
    orientation: 'horizontal'
    padding: 10, 10, 10, 10
    cols: 2
    Image:
        id: inpimg
        source: './icons/user_inp.png'
        x: root.x + 10
        y: root.y + 10
        width: root.width - 40
        height: max(40, scrlv.height)
        size_hint: 0.9, None
        allow_stretch: True
        keep_ratio: False
        ScrollView:
            id: scrlv
            x: root.ids['inpimg'].x + 10
            y: root.ids['inpimg'].y
            width: root.width - 80
            height: (len(usrinp._lines)+1) * usrinp.line_height
            TextInput:
                id: usrinp
                valign: 'middle'
                halign: 'left'
                font_size: 16
                multiline: True
                size_hint: 1, None
                height: scrlv.height
                background_color: 0, 0, 0, 0

Using the height: (len(usrinp._lines)+1 *usrinp.line_height will auto-size the textbox on each newline. Here's how it looks:

Image

Additionally, if you want to limit the size after a certain number of lines, you can do:

height: (len(usrinp._lines)+1) * usrinp.line_height if (len(usrinp._lines)+1 <= number_of_lines) else number_of_lines * usrinp.line_height

I have to find a way to reimplement the scroll bar in this because the text just refuses to go up by touching/ clicking.

like image 45
Takusui Avatar answered Oct 17 '25 21:10

Takusui