Search code examples
pythonandroidkivybuildozer

Buildozer compiled apk doesn't keep font size


I'm trying to learn python and kivy by writing an app which dynamically creates modules inputted by the user in order to be counted using + and - buttons. I am using buildozer to create the apk and deploy it to my phone (Samsung Galaxy S21 Ultra, Android 11). I have encountered two problems:

  1. Though there is no problem when I run the code in a virtual environment in PyCharm, when I run the apk on the phone, it does not keep the size of the text that I set in the code;
  2. Pdf file is being created in the virtual environment in PyCharm but it crashes the apk on the phone. Any help will be very much appreciated. Thanks a lot. Here is the full code:

Python file:

from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from fpdf import FPDF


class pdf(FPDF): # Setting the header and footer for the pdf document
    def header(self):
        self.image('inventory_management.png', 10, 8, 25)
        self.set_font('helvetica', 'B', 20)
        self.cell(0,10, app.root.ids.project_name.text, ln=True, align='C')
        self.ln(20)

    def footer(self):
        self.set_y(-15)
        self.set_font('helvetica', 'I', 10)
        self.cell(0, 10, f'Page {self.page_no()}/{{nb}}', align='C')


class popup_empty(Popup): # Message box if user doesn't inputs a module name
    pass


class popup_exist(Popup): # Message box if user inputs an existent module name
    pass


class Row(BoxLayout): # Creates a row for each module
    quantity = ObjectProperty()
    entry = ObjectProperty()

    def change_label(self): # Setting the module name with the user input
        self.name_label.text = app.root.ids.name_input.text

    def add_entry(self): # Function used by the + button to add to the quantity
        self.quantity.text = str(int(self.quantity.text) + int(self.entry.text))
        app.root.Lista_module[self.ids.name_label.text] = int(self.quantity.text)

    def deduct_entry(self): # Function used by the - button to deduct from the quantity
        self.quantity.text = str(int(self.quantity.text) - int(self.entry.text))
        app.root.Lista_module[self.ids.name_label.text] = int(self.quantity.text)

    def del_row(self): # Function used by the del button to remove a module row
        del app.root.Lista_module[self.ids.name_label.text]
        app.root.ids.rows_container.remove_widget(self)


class mainContainer(BoxLayout): # Main container which holds all the widgets

    Lista_module = {}

    def file_name(self): # replaces the spaces user inputs in the module name to create the pdf filename
        name = self.ids.project_name.text
        name = name.replace(" ", "_")
        return name

    def add_a_row(self): # function used to dynamically add rows to the scrollview

        if self.ids.name_input.text != "":
            name = self.ids.name_input.text
            exist = False
            for key in self.Lista_module.keys():
                if key == name:
                    exist = True
            if exist:
                popup = popup_exist()
                popup.open()
            else:
                temp_row = Row()
                temp_row.change_label()
                self.ids.rows_container.add_widget(temp_row)
                key = self.ids.name_input.text
                self.Lista_module[key] = 0
        else:
            popup = popup_empty()
            popup.open()
    pass

    def print(self): # function used by the print button to create the pdf file
        name = self.file_name() + '.pdf'
        document = pdf('P', 'mm', 'A4')
        document.add_page()
        document.alias_nb_pages()
        document.set_auto_page_break(auto=True)
        document.set_font('times', '', 14)
        for mod in self.Lista_module:
            document.cell(0, 10, f'{mod}: {self.Lista_module[mod]}', border=True, ln=True)
        document.output('I', name)


class lysuApp(App):

    def build(self):
        return mainContainer()


if __name__ == "__main__":
    app = lysuApp()
    app.run()

kv file:

<popup_exist>
    size_hint: 0.5, 0.5
    pos_hint: {"x":0.2, "top":0.9}
    title: "Eroare nume"
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height
        Label:
            text: "Modul existent, reintrodu!"

        Button:
            text: "OK"

            on_release: root.dismiss()

<popup_empty>
    size_hint: 0.5, 0.5
    pos_hint: {"x":0.2, "top":0.9}
    title: "Eroare nume"
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height
        Label:
            text: "Trebuie sa introduci un nume!"

        Button:
            text: "OK"

            on_release: root.dismiss()

<Row>
    name_label: name_label
    quantity: quantity
    entry: entry
    orientation: "horizontal"
    size_hint_y: None
    height: 30
    id: root.module_name
    Label:
        id: name_label
        font_size: 20
        text: ""
    Label:
        font_size: 20
        text: ":"
    Label:
        id: quantity
        font_size: 20
        text: "0"
    TextInput:
        id: entry
        font_size: 20
        text: "1"
    Button:
        font_size: 20
        text: "-"
        on_press: root.deduct_entry()
    Button:
        font_size: 20
        text: "+"
        on_press: root.add_entry()
    Button:
        font_size: 20
        text: "del"
        on_press: root.del_row()


<mainContainer>

    id: mainpage
    BoxLayout: # the main container
        orientation: "vertical"
        size: root.width, root.height
        padding: 25
        spacing: 20
        BoxLayout: # Contains the title
            orientation: "vertical"
            size_hint: (1, .2)
            spacing: 5
            Label:
                font_size: 20
                text: "Creaza modulele si incepe editarea!"
                size_hint: (1, .5)

            BoxLayout: # Box for project name and print button
                size_hint: (1, .5)
                orientation: "horizontal"
                Label:
                    font_size: 20
                    text: "Numeste proiectul: "
                TextInput:
                    id: project_name
                    font_size: 20
                Button:
                    font_size: 20
                    text: "Printeaza"
                    on_release: app.root.print()

        ScrollView: # Will hold the dynamically created rows
            BoxLayout:
                size_hint_y: None
                height: self.minimum_height
                row_force_default: True
                row_default_height: dp(40)
                orientation: "vertical"
                id: rows_container
                spacing: 10
        BoxLayout: # Bottom of the page used to input the name of the modules that will be dynamically created
            orientation: "horizontal"
            size_hint: (1, .1)
            Label:
                font_size: 20
                text: "Nume modul"
            TextInput:
                id: name_input
                font_size: 20
            Button:
                font_size: 20
                text: "Adauga"
                on_press:
                    root.add_a_row()


Solution

  • This is because you are setting your font sizes in terms of pixels, which varies across screens. You can set the font sizes based on measurements (inches, centimeters) or pixel density as follows:

    In your .kv file, instead of font_size: 20, use font_size: '20dp', font_size: '20cm', or whatever your desired unit is.

    In you want to set font sizes in a .py file, first import the desired unit from kivy.metrics. For example, if you wanted to use inches, you would write from kivy.metrics import inch and then replace numeric pixel values with inch(2), inch(1), or whatever value you want.

    See Metrics for more.

    As for your second question, the line document.output('I', name) is a typo (it should be document.output(name, "F") if you are creating a file with the name name). If that is not the cause of the issue, look into debugging your APK with logcat.

    In the future, please separate questions into two separate posts.