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:
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()
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.