Kivy – Add buttons dynamically with referring to root atributes

so I try to break down my problem:

I have two screens and when I switch from one screen to the other it should dynamically generate buttons on the second screen (id: “thema_screen“). The buttons are created at the second screen into a GridLayout, which has the id: “grid_thema_screen

Now I want the font_size of the buttons to change automatically, if I change the window size, which works pretty well with font_size: min(root.height, root.width) / 10 in the kivy-file, but it’s not working, when I write it in the python-file add_widget(Button(text = str(i+2), font_size = min(self.root.height, self.root.width) / 2))

It changes the font-size once, but then if I resice the window, the font isn’t changing anymore. Here is the code snippet of my python file:

class Wurzel(MDBoxLayout):

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

def changeScreen(self, next_screen):
    if next_screen == "thema_screen":
        self.ids.wurzel_screen_manager.current = next_screen

        for i in range(12):
            self.ids.thema_screen.ids.grid_thema_screen.add_widget(Button(text = str(i+2), font_size = min(self.root.height,
                                                                                          self.root.width) / 10)) 

And here my kivy File:

<Wurzel>:
orientation: 'vertical'
spacing: 20

MDToolbar:
    title: 'Hellllooo'
    left_action_items: [["menu", lambda x: app.navigation_klick()], ["apple", lambda x: app.navigation_klick()]]
    elevation: 8

ScreenManager:
    id: wurzel_screen_manager
    StartScreen:
        name: "start_screen"
    ThemaScreen:
        id: thema_screen
        name: "thema_screen"

<[email protected]>:

BoxLayout:
    orientation: "vertical"

   ...

<[email protected]>:
    GridLayout:
        id: grid_thema_screen
        cols: 3

    padding: root.width * .01, root.height * .01
    spacing: min(root.width, root.height) * .02


    Button:
        text: "1"
        font_size: min(root.height, root.width) / 10
        size_hint: None, None
        size: self.font_size*3, self.font_size*3

So it would be really nice, if someone could help me and tell me, why the fontsize isn’t changing automatically anymore, if I create the buttons dynamically in Python. Thanks a lot.

Answer

So the reason why the font size doesn’t change when you add the buttons programatically is because the font_size attribute is not bound to anything. When you create a widget in the kv file, the interpreter will automatically bind your properties to one another. This means that when you enter:

font_size: min(root.height, root.width) / 10

in the kv file, when root.height is updated, so is font_size. However, writing

Button(font_size = min(self.root.height, self.root.width) / 2)

in your Python file creates a Button whose font_size attribute is defined by the values you passed at that instance.

There are several things you could do, you could create NumericProperty in your Wurzel class and bind your Buttons to this property (see https://kivy.org/doc/stable/api-kivy.properties.html for more details). However, since your having the issues with resizing, I think the easiest thing to do is take advantage of the on_size call back (see https://kivy.org/doc/stable/api-kivy.event.html for more details).

Here is what the Wurzel class should look like:

class Wurzel(MDBoxLayout):

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

    def changeScreen(self, next_screen):
        if next_screen == "thema_screen":
            self.ids.wurzel_screen_manager.current = next_screen

            for i in range(12):
                self.ids.thema_screen.ids.grid_thema_screen.add_widget(Button(text = str(i+2), font_size = min(self.root.height, self.root.width) / 10)) 

    def update_font_size(self, *args):
        for button in self.children:  # Loop through all children
            if isinstance(button, Button):  # Check if child is a button (may not need)
                button.font_size = min(self.root.height, self.root.width) / 10))  # Update font_size

    on_size = update_font_size  # Set a callback for on_size