I am building an app which serves as a Travel expense manager. I am currently trying to build a system in which you insert the requested amount on an MDTextField and press a button to confirm request. At the same time, on other widget I will like to be adding up the total amount requested.
i.e. If I write 1000 on the TextField and click on the button 'Ingresar Gasto' the value below the Label 'MONTO TOTAL SOLICITADO' should update and both the target MDTextField and the MDTextField with the origin number should have a correctly formated $ 1,000.00.
The same needs to hold true for all the expansion panels in which I have the same widgets.
I have tried the following:
Kivy code of the expansion panel:
<MyContentAliment>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_aliment_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_aliment_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.sumar_gasto()
Kivy code of the MDCard (containing the target widget):
<TravelManagerWindow>:
BoxLayout:
size_hint:1,0.85
pos_hint: {"center_x": 0.5, "center_y":0.37}
adaptive_height:True
height: self.minimum_height
ScrollView:
adaptive_height:True
GridLayout:
id: container
size_hint_y: None
cols: 1
row_default_height: root.height*0.10
height: self.minimum_height
MDBoxLayout:
adaptive_height: True
orientation: 'horizontal'
GridLayout:
id: panel_container
size_hint_x: 0.6
cols: 1
adaptive_height: True
MDBoxLayout:
size_hint_x: 0.05
MDCard:
id: resumen_solicitud
size_hint: None, None
size: "250dp", "300dp"
pos_hint: {"top": 0.9, "center_x": .5}
elevation: 0.1
MDBoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0.8, 0.8, 0.8, 1
Rectangle:
pos: self.pos
size: self.size
MDLabel:
text: 'Monto Total Solicitado'
font_style: 'Button'
halign: 'center'
font_size: (root.width**2 + root.height**2) / 15.5**4
size_hint_y: 0.2
MDSeparator:
height: "1dp"
MDTextField:
id: suma_solic_viaje
text: "$ 0.00"
bold: True
line_color_normal: app.theme_cls.primary_color
halign: "center"
size_hint_x: 0.8
Last but not least, the Python code:
class TravelManagerWindow(Screen):
viajeInicio = ObjectProperty(None)
panel_container = ObjectProperty(None)
travel_list = ObjectProperty(None)
DateMDTextField = ObjectProperty(None)
menu = ObjectProperty()
# EXPANSION PANEL PARA SOLICITAR GV
def set_expansion_panel(self):
#FOOD PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food.png",
content=MyContentAliment(),
panel_cls=MDExpansionPanelOneLine(
text="Alimentacion")))
# CASETAS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(
icon="casetas.png",
content=MyContentCasetas(),
panel_cls=MDExpansionPanelOneLine(
text="Casetas")))
# GAS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="gas.png",
content=MyContentGasolina(),
panel_cls=MDExpansionPanelOneLine(
text="Gasolina")))
# HOSPEDAJE PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(
icon="hospedaje.png", content=MyContentHosped(),
panel_cls=MDExpansionPanelOneLine(
text="Hospedaje")))
# VARIOS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(
icon="varios.png", content=MyContentVarios(),
panel_cls=MDExpansionPanelOneLine(
text="Varios")))
ALL OF THE PANEL CONTAINERS HAVE THE SAME CODE, ONLY REFERENCING TO DIFFERENT WIDGETS (WERE NOT ADDED FOR SIMPLICITY)
class MyContentAliment(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_aliment_viaje.text) <= 3 and
(self.ids.monto_aliment_viaje.text).isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_aliment_viaje.text) == 4 and
(self.ids.monto_aliment_viaje.text).isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text[0] + "," + \
self.ids.monto_aliment_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_aliment_viaje.text) == 5 and
(self.ids.monto_aliment_viaje.text).isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text[:2] + "," + \
self.ids.monto_aliment_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_aliment_viaje.text) > 5 and
self.ids.monto_aliment_viaje.text.startswith('$') == False:
self.ids.monto_aliment_viaje.text = self.ids.monto_aliment_viaje.text[:-1]
def sumar_gasto(self):
if self.ids.monto_aliment_viaje.text == "":
pass
else:
travel_manager = TravelManagerWindow()
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_aliment_viaje.text)
travel_manager.ids.suma_solic_viaje.text= "$ " + str(monto_total)
self.apply_currency_format()
### WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
ScreenManager().add_widget(LoginWindow(name='login'))
ScreenManager().add_widget(CreateAccountWindow(name='create'))
ScreenManager().add_widget(MainWindow(name='main'))
ScreenManager().add_widget(IngActivWindow(name='ingActiv'))
ScreenManager().add_widget(CronogramaWindow(name='cronograma'))
ScreenManager().add_widget(TravelManagerWindow(name='travelManager'))
ScreenManager().add_widget(SoporteTecnicoWindow(name='soporteTecnico'))
class powerApp2(MDApp):
pass
if __name__ == "__main__":
powerApp2().run()
Currently I get the correct formats due to the apply_currency_format function. Nevertheless, when I press the button, the value of the target text field remains unchanged.
Thanks a lot in advance.
CODE FOR MINIMAL REPRODUCIBLE EXAMPLE:
Python Code:
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelOneLine
from kivy.uix.boxlayout import BoxLayout
class MyContentAliment(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_aliment_viaje.text) <= 3 and self.ids.monto_aliment_viaje.text.isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_aliment_viaje.text) == 4 and self.ids.monto_aliment_viaje.text.isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text[0] + "," + \
self.ids.monto_aliment_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_aliment_viaje.text) == 5 and self.ids.monto_aliment_viaje.text.isnumeric():
self.ids.monto_aliment_viaje.text = "$" + self.ids.monto_aliment_viaje.text[:2] + "," + \
self.ids.monto_aliment_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_aliment_viaje.text) > 5 and self.ids.monto_aliment_viaje.text.startswith('$') == False:
self.ids.monto_aliment_viaje.text = self.ids.monto_aliment_viaje.text[:-1]
def sumar_gasto(self):
if self.ids.monto_aliment_viaje.text == "":
pass
else:
travel_manager = TravelManagerWindow()
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_aliment_viaje.text)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.apply_currency_format()
class MyContentCasetas(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_casetas_viaje.text) <= 3 and self.ids.monto_casetas_viaje.text.isnumeric():
self.ids.monto_casetas_viaje.text = "$" + self.ids.monto_casetas_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_casetas_viaje.text) == 4 and self.ids.monto_casetas_viaje.text.isnumeric():
self.ids.monto_casetas_viaje.text = "$" + self.ids.monto_casetas_viaje.text[0] + "," + \
self.ids.monto_casetas_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_casetas_viaje.text) == 5 and self.ids.monto_casetas_viaje.text.isnumeric():
self.ids.monto_casetas_viaje.text = "$" + self.ids.monto_casetas_viaje.text[:2] + "," + \
self.ids.monto_casetas_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_casetas_viaje.text) > 5 and self.ids.monto_casetas_viaje.text.startswith('$') == False:
self.ids.monto_casetas_viaje.text = self.ids.monto_casetas_viaje.text[:-1]
class MyContentGasolina(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_gas_viaje.text) <= 3 and self.ids.monto_gas_viaje.text.isnumeric():
self.ids.monto_gas_viaje.text = "$" + self.ids.monto_gas_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_gas_viaje.text) == 4 and self.ids.monto_gas_viaje.text.isnumeric():
self.ids.monto_gas_viaje.text = "$" + self.ids.monto_gas_viaje.text[0] + "," + \
self.ids.monto_gas_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_gas_viaje.text) == 5 and self.ids.monto_gas_viaje.text.isnumeric():
self.ids.monto_gas_viaje.text = "$" + self.ids.monto_gas_viaje.text[:2] + "," + \
self.ids.monto_gas_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_gas_viaje.text) > 5 and self.ids.monto_gas_viaje.text.startswith('$') == False:
self.ids.monto_gas_viaje.text = self.ids.monto_gas_viaje.text[:-1]
class MyContentHosped(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_hosped_viaje.text) <= 3 and self.ids.monto_hosped_viaje.text.isnumeric():
self.ids.monto_hosped_viaje.text = "$" + self.ids.monto_hosped_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_hosped_viaje.text) == 4 and self.ids.monto_hosped_viaje.text.isnumeric():
self.ids.monto_hosped_viaje.text = "$" + self.ids.monto_hosped_viaje.text[0] + "," + \
self.ids.monto_hosped_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_hosped_viaje.text) == 5 and self.ids.monto_hosped_viaje.text.isnumeric():
self.ids.monto_hosped_viaje.text = "$" + self.ids.monto_hosped_viaje.text[:2] + "," + \
self.ids.monto_hosped_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_hosped_viaje.text) > 5 and self.ids.monto_hosped_viaje.text.startswith('$') == False:
self.ids.monto_hosped_viaje.text = self.ids.monto_hosped_viaje.text[:-1]
class MyContentVarios(BoxLayout):
def apply_currency_format(self):
# if len <= 3
if len(self.ids.monto_varios_viaje.text) <= 3 and self.ids.monto_varios_viaje.text.isnumeric():
self.ids.monto_varios_viaje.text = "$" + self.ids.monto_varios_viaje.text + '.00'
# n,nnn
elif len(self.ids.monto_varios_viaje.text) == 4 and self.ids.monto_varios_viaje.text.isnumeric():
self.ids.monto_varios_viaje.text = "$" + self.ids.monto_varios_viaje.text[0] + "," + \
self.ids.monto_varios_viaje.text[1:] + '.00'
# nn,nnn
elif len(self.ids.monto_varios_viaje.text) == 5 and self.ids.monto_varios_viaje.text.isnumeric():
self.ids.monto_varios_viaje.text = "$" + self.ids.monto_varios_viaje.text[:2] + "," + \
self.ids.monto_varios_viaje.text[2:] + '.00'
def limit_currency(self):
if len(self.ids.monto_varios_viaje.text) > 5 and self.ids.monto_varios_viaje.text.startswith('$') == False:
self.ids.monto_varios_viaje.text = self.ids.monto_varios_viaje.text[:-1]
class LoginWindow(Screen):
pass
class TravelManagerWindow(Screen):
panel_container = ObjectProperty(None)
# EXPANSION PANEL PARA SOLICITAR GV
def set_expansion_panel(self):
# FOOD PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food", content=MyContentAliment(),
panel_cls=MDExpansionPanelOneLine(text="Alimentacion")))
# CASETAS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food", content=MyContentCasetas(),
panel_cls=MDExpansionPanelOneLine(text="Casetas")))
# GAS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food", content=MyContentGasolina(),
panel_cls=MDExpansionPanelOneLine(text="Gasolina")))
# HOSPEDAJE PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food", content=MyContentHosped(),
panel_cls=MDExpansionPanelOneLine(text="Hospedaje")))
# VARIOS PANEL
self.ids.panel_container.add_widget(MDExpansionPanel(icon="food", content=MyContentVarios(),
panel_cls=MDExpansionPanelOneLine(text="Varios")))
### WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
ScreenManager().add_widget(LoginWindow(name='login'))
ScreenManager().add_widget(TravelManagerWindow(name='travelManager'))
class reprodExample(MDApp):
def build(self):
self.theme_cls.primary_palette = "Teal"
return WindowManager()
if __name__ == "__main__":
reprodExample().run()
Code for KV File:
<WindowManager>:
LoginWindow:
TravelManagerWindow:
<LoginWindow>:
MDRaisedButton:
text: 'Enter'
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint: None, None
on_release:
root.manager.transition.direction = 'up'
root.manager.current = 'travelManager'
<TravelManagerWindow>:
name:'travelManager'
on_pre_enter: root.set_expansion_panel()
BoxLayout:
orientation: 'vertical'
size_hint:1,0.85
pos_hint: {"center_x": 0.5, "center_y":0.37}
adaptive_height:True
height: self.minimum_height
ScrollView:
adaptive_height:True
GridLayout:
size_hint_y: None
cols: 1
row_default_height: root.height*0.10
height: self.minimum_height
BoxLayout:
adaptive_height: True
orientation: 'horizontal'
GridLayout:
id: panel_container
size_hint_x: 0.6
cols: 1
adaptive_height: True
BoxLayout:
size_hint_x: 0.05
MDCard:
id: resumen_solicitud
size_hint: None, None
size: "250dp", "300dp"
pos_hint: {"top": 0.9, "center_x": .5}
elevation: 0.1
MDBoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0.8, 0.8, 0.8, 1
Rectangle:
pos: self.pos
size: self.size
MDLabel:
text: 'Monto Total Solicitado'
font_style: 'Button'
halign: 'center'
font_size: (root.width**2 + root.height**2) / 15.5**4
size_hint_y: 0.2
MDSeparator:
height: "1dp"
MDTextField:
id: suma_solic_viaje
text: "$ 0.00"
bold: True
line_color_normal: app.theme_cls.primary_color
halign: "center"
size_hint_x: 0.8
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDSeparator:
height: "1dp"
BoxLayout:
id: expense_graph
halign: 'center'
<MyContentAliment>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_aliment_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_aliment_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.sumar_gasto()
### CASETAS
<MyContentCasetas>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_casetas_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
#input_filter: 'float'
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_casetas_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.apply_currency_format()
BoxLayout:
size_hint_x: 0.05
### GASOLINA
<MyContentGasolina>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_gas_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
#input_filter: 'float'
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_gas_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.apply_currency_format()
BoxLayout:
size_hint_x: 0.05
### HOSPEDAJE
<MyContentHosped>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_hosped_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
#input_filter: 'float'
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_hosped_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.apply_currency_format()
BoxLayout:
size_hint_x: 0.05
### VARIOS
<MyContentVarios>:
adaptive_height: True
MDBoxLayout:
orientation:'horizontal'
adaptive_height:True
size_hint_x:self.width
pos_hint: {"center_x":0.5, "center_y":0.5}
spacing: dp(10)
padding_horizontal: dp(10)
MDLabel:
text: 'Monto:'
multiline: 'True'
halign: 'center'
pos_hint: {"x":0, "top":0.5}
size_hint_x: 0.15
font_style: 'Button'
font_size: 19
MDTextField:
id: monto_varios_viaje
hint_text: 'Monto a solicitar'
pos_hint: {"x":0, "top":0.5}
halign: 'left'
size_hint_x: 0.3
helper_text: 'Ingresar el monto a solicitar'
helper_text_mode: 'on_focus'
write_tab: False
#input_filter: 'float'
required: True
on_text:
root.limit_currency()
MDRaisedButton:
id: boton_varios_viaje
pos_hint: {"x":0, "top":0.5}
text:'Ingresar Gasto'
on_release:
root.apply_currency_format()
BoxLayout:
size_hint_x: 0.05
In your
sumar_gasto()
method the line:is creating a new instance of
TravelManagerWindow
that is unrelated to the instance that is displayed in your GUI. So any changes you make to that instance will have no effect on your GUI.Without seeing more of your code, I cannot guess how you might access the instance of
TravelManagerWindow
that is actually in your GUI.So, either you can figure that out for yourself, or you can post a minimal, complete, verifiable example.
So, with the additional code posted, I think you can replace:
with:
This works because the
root
widget of theMDApp
is theWindowManager
.You should also add a
name
for theLoginWindow
in thekv
:I also noticed that you have some unnecessary code:
The above lines have no effect, for the same reason as did the
travel_manager = TravelManagerWindow()
code. CallingScreenManager()
creates a new instance ofScreenManager
that is not in your GUI, and adding aWidget
to that instance will have no effect on your GUI. The rule forWindowManager
at the start of thekv
will build the twoScreens
and add then to theWindowManager
.