Plug Fire
Plug Fire

Reputation: 127

Why won't my Kivy program update the font size when I tell it to?

I'm making a choose your own adventure game, but sometimes I need to change the font size and Kivy isn't giving me the results I'm expecting. This is the full code so feel free to run it and see what I mean. Here is the python file:

# A Choose your own adventure game
import kivy
kivy.require('1.11.1') 

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder

global root
root = BoxLayout() #If I don't define root immediately the program won't work
                   #root is given a proper definition in class Main()

#Easily add new pages to the program
def add_page(pagenum):
    root.clear_widgets()
    root.add_widget(pagenum)    

#The main window that encapsulates all other widgets
class RootBoxLayout(BoxLayout): 
    def __init__(self, **kwargs):
        super(RootBoxLayout, self).__init__(**kwargs)

# The Menu that drives the game
class Menu(BoxLayout):  
    def __init__(self, **kwargs):
        super(Menu, self).__init__(**kwargs)

# The Main Menu
class StartMenu(Menu):
    def __init__(self, **kwargs):
        super(Menu, self).__init__(**kwargs)
                
        #Text Box
        self.ids.textbox.text = "Opening Screen"
        
        # Button 1
        self.ids.button1.text = "Play"
        self.ids.button1.bind(on_press = self.nextpage1)
        
    def nextpage1(self, *args):
        add_page(HappyBee())
    
        
class HappyBee(Menu):
    def __init__(self, **kwargs):
        super(Menu, self).__init__(**kwargs)
        
        #############################################
        ### This is where the problem seems to be ###
        #############################################
        self.ids.textbox.font_size = self.ids.textbox.height/10             #Kivy says nah I don't feel like doing this
        self.ids.textbox.text = "This is a very large block of text that I would like " \
        "to decrease the font size of.  Pressing the button below changes it but I don't " \
        "want users to have to press a button just to get the game to function " \
        "how it should function from the start."
        
        # Button 1
        self.ids.button1.text = "y tho"
        self.ids.button1.bind(on_press = self.nextpage1)
    
    # What to do when each button is pressed
    def nextpage1(self, *args):
        self.ids.textbox.font_size = self.ids.textbox.height/10             # Kivy says ok I can change it now lol

# An App class that will be used to umbrella everything else in the application
class Main(App):
    def build(self):
        Builder.load_file("cyoa.kv")
        global root # Other classes and functions need to easily access root
        root = RootBoxLayout()
        first_screen = StartMenu()
        add_page(first_screen) # Add the Main Menu to the root window
        return root

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

and here is the corresponding kv file, which I have saved as cyoa.kv

<RootBoxLayout>:
    orientation: 'vertical'
    
    # Create the background color of the root layout
    canvas.before:
        Color:
            rgba: 0,0,0,1 # black
        Rectangle:
            pos: self.pos
            size: self.size

# This custom button allows to font size to change dynamically with the window
<MyButton@Button>:
    font_size: self.height/3
    halign: 'center'
    valign: 'center'
    text_size: self.size
    size_hint_y: 0.14

<Menu>:
    BoxLayout:
        orientation: 'vertical'
        Label:
            id: textbox
            font_size: self.height/6
            text_size: self.size # Allows text to wrap
            halign: 'center'
            valign: 'center'
            size_hint_y: 0.6

        MyButton:
            id: button1
            text: 'Play'

Upvotes: 1

Views: 231

Answers (1)

furas
furas

Reputation: 142641

I can change font_size in __init__ only if I remove font_size from .kv. It seems it gets value from .kv after running __init__ and this makes problem. There is also other problem: height (and width) in __init__ is 100 instead of expected size. Probably it calculates it after running __init__.


Searching in internet I found on Reddit: How can I use init for screen ids?

It uses Clock to run some function after all updates and in this function change values.

def __init__(self, **kwargs):
    #super(...)
    Clock.schedule_once(self._do_setup)

def _do_setup(self, *l):
    self.ids.something = '....'

In your code it would be

from kivy.clock import Clock  # <---

class HappyBee(Menu):

    def __init__(self, **kwargs):
        super(Menu, self).__init__(**kwargs)
        
        self.ids.textbox.text = "This is a very large block of text that I would like " \
        "to decrease the font size of.  Pressing the button below changes it but I don't " \
        "want users to have to press a button just to get the game to function " \
        "how it should function from the start."
        
        self.ids.button1.text = "y tho"
        self.ids.button1.bind(on_press = self.nextpage1)

        Clock.schedule_once(self.on_init_complete)  # <---
        
    def on_init_complete(self, *args, **kwargs):
        self.ids.textbox.font_size = self.ids.textbox.height/10  # <---
                   

It works but has one small problem - it display text in original size for few milliseconds. But if you don't know this then you may not notice this.


EDIT: Similar problem: How to Load Kivy IDs Before Class Method is Initialized (Python with Kivy)

Upvotes: 2

Related Questions