Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically resizing a kivy label (and button) on the python side

How do I dynamically resize the a label or button, in particular, the text_size and height, depending on the amount of text, at run-time?

I am aware that this question has already been answered in one way with this question:

Dynamically resizing a Label within a Scrollview?

And I reflect that example in part of my code.

The problem is dynamically resizing the labels and buttons at run-time. Using, for example:

btn = Button(text_size=(self.width, self.height), text='blah blah')

...and so on, only makes the program think (and logically so) that the "self" is referring to the class which is containing the button.

So, how do I dynamically resize these attributes in the python language, not kivy?

My example code:

import kivy
kivy.require('1.7.2') # replace with your current kivy version !

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout

i = range(20)

long_text = 'sometimes the search result could be rather long \
sometimes the search result could be rather long \
sometimes the search result could be rather long '

class ButtonILike(Button):

    def get_text(self):
        return long_text

class HomeScreen(Screen):
    scroll_view = ObjectProperty(None)

    def __init__(self, *args, **kwargs):
        super(HomeScreen, self).__init__(*args, **kwargs)
        layout1 = GridLayout(cols=1, spacing=0, size_hint=(1, None), \
            row_force_default=False, row_default_height=40)
        layout1.bind(minimum_height=layout1.setter('height'),
                     minimum_width=layout1.setter('width'))
        layout1.add_widget(ButtonILike())

        for result in i:

                btn1 = Button(font_name="data/fonts/DejaVuSans.ttf", \
                    size_hint=(1, None), valign='middle',)#, \
                    #height=self.texture_size[1], text_size=(self.width-10, None))
                btn1.height = btn1.texture_size[1]
                btn1.text_size = (btn1.width-20, layout1.row_default_height)
                btn1.text = long_text

                btn2 = Button(font_name="data/fonts/DejaVuSans.ttf", \
                    size_hint=(1, None), valign='middle')

                btn2.bind(text_size=(btn2.width-20, None))
                btn2.text = 'or short'

                layout1.add_widget(btn1)
                layout1.add_widget(btn2)


        scrollview1 = self.scroll_view
        scrollview1.clear_widgets()
        scrollview1.add_widget(layout1)


class mybuttonsApp(App):

    def build(self):

        return HomeScreen()



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

And the kv file:

#:kivy 1.7.2

<ButtonILike>:
    text_size: self.width-10, None
    size_hint: (1, None)
    height: self.texture_size[1]
    text: root.get_text()
    #on_release: root.RunSearchButton_pressed()

<HomeScreen>:
    scroll_view: scrollviewID
    AnchorLayout:
        size_hint: 1, .1   
        pos_hint: {'x': 0, 'y': .9}
        anchor_x: 'center'
        anchor_y: 'center'
        Label:
            text: 'Button Tester'

    ScrollView:
        id: scrollviewID
        orientation: 'vertical'
        pos_hint: {'x': 0, 'y': 0}
        size_hint: 1, .9
        bar_width: '8dp'

You can see that I added the button from the kv file which displays all the behavior that I want at the top of the list. Resize your window while running it, and you can see the magic. And, of course, changing the text_size also makes it possible for me to align text.

I simply have not been able to achieve the same behavior on the python side. My app requires that the buttons be created at run-time. I think the answer might lie with "bind()", though admittedly, I'm not sure I used it correctly in my attempts or that I understand it fully. You can see that I tried with "btn2", which I thought would've thrown the text to the left (since halign defaults to left), but didn't seem to do anything.

I appreciate the help.

like image 997
bosky Avatar asked Oct 02 '22 18:10

bosky


2 Answers

I think the best way is to set Label's/Button's size to texture_size:

Label:
    text: "test"
    size_hint: None, None
    size: self.texture_size

    canvas.before: # for testing purposes
        Color:
            rgb: 0, 1, 0
        Rectangle:
            pos: self.pos
            size: self.size
like image 111
martin Avatar answered Oct 05 '22 11:10

martin


My answer is slightly different from @martin's - I only want to modify the height.

def my_height_callback(obj, texture: Texture):

    if texture:
         obj.height = max(texture.size[1], 100)

class MyButton(Button):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.size_hint = (1, None)
        self.bind(texture=my_height_callback)

When the text is rendered the texture property of the button gets set. That texture's height is then pushed to the button's height via the callback. Calling max() allows for a minimum height to be set. This works fine with labels as well.

like image 21
James Moore Avatar answered Oct 05 '22 13:10

James Moore