Python 上widgets的交互和删除 + KivyMD和代码优化
Interaction and Deletion among widgets on Python + KivyMD and Code Optimization
我目前正在构建一个用作差旅费用管理器的应用程序。我有一个系统,其中用户在 MDTextField 上写入所需的费用金额,此类费用将记录在 MDList 中,请求的费用总额将添加到 MDTextField。为清楚起见,我将 post 截图:
到目前为止,所有系统都可以正常工作。但是,用户可能会犯错误。我希望用户能够在按下垃圾桶图标时从 MDList 中删除一个项目。同时,应从请求的总金额中减去已删除的支出金额。 (即,如果用户删除了 Alimentación 中包含 $1,000.00 的元素,则删除后请求的总金额应为 $2000.0)。
在我的代码中,我已经能够将图标的 on_pressed 事件绑定到 remove_item 函数。成功完成所需的减法,之后将显示成功 toast。然而,这是在没有实际从 MDList 中删除项目的情况下完成的。如第二张截图所示,总费用金额为0,但MDList项并没有被删除(remove_widget函数在我的remove_item函数中没有做所需的操作)。
最小可重现示例代码:
Python代码:
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
from kivymd.uix.list import TwoLineIconListItem, IconLeftWidget
from kivymd.toast import toast
class ViaticosIconList(TwoLineIconListItem):
pass
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
elif self.ids.monto_aliment_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
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()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Alimentación Personal", secondary_text=self.ids.monto_aliment_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_aliment_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_aliment_viaje.text = ''
def show_toast(self):
toast("Monto de Alimentación Personal eliminado de la solicitud")
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]
def sumar_gasto(self):
if self.ids.monto_casetas_viaje.text == "":
pass
elif self.ids.monto_casetas_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_casetas_viaje.text)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.apply_currency_format()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Casetas", secondary_text=self.ids.monto_casetas_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_casetas_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_casetas_viaje.text = ''
def show_toast(self):
toast("Monto de Casetas eliminado de la solicitud")
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]
def sumar_gasto(self):
if self.ids.monto_gas_viaje.text == "":
pass
elif self.ids.monto_gas_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_gas_viaje.text)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.apply_currency_format()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Gasolina", secondary_text=self.ids.monto_gas_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_gas_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_gas_viaje.text = ''
def show_toast(self):
toast("Monto de Gasolina eliminado de la solicitud")
class LoginWindow(Screen):
pass
class TravelManagerWindow(Screen):
panel_container = ObjectProperty(None)
# EXPANSION PANEL PARA SOLICITAR GV
def set_expansion_panel(self):
self.ids.panel_container.clear_widgets()
# 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")))
### WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
class ReprodExample(MDApp):
def build(self):
self.theme_cls.primary_palette = "Teal"
return WindowManager()
if __name__ == "__main__":
ReprodExample().run()
KV 文件:
<WindowManager>:
LoginWindow:
TravelManagerWindow:
<LoginWindow>:
name: 'login'
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()
MDRaisedButton:
text: 'Back'
pos_hint: {'center_x': 0.5, 'center_y': 0.85}
size_hint: None, None
on_release:
root.manager.transition.direction = 'down'
root.manager.current = 'login'
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", "350dp"
pos_hint: {"top": 0.9, "center_x": .5}
elevation: 0.1
BoxLayout:
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"
MDBoxLayout:
padding: '5dp', '10dp', '5dp', '10dp'
MDList:
pos_hint: {'x': 0, 'top': 1}
id: viaticos_list
padding: 0
<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
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.sumar_gasto()
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
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.sumar_gasto()
BoxLayout:
size_hint_x: 0.05
最后,如果您能给我 Python 文件的代码优化建议,我将不胜感激。我在我的 类 中重复基本相同的代码,只是指的是不同的小部件。我可以列出我想与之交互的小部件并进行循环,得到相同的结果吗?我是 Python 的新手,所以我想我需要学习更好的编码方法。
提前致谢。
问题是您的 remove_item()
试图删除错误的对象。传递给 remove_item()
的 instance
是图标,而不是 ViaticosIconList
。为了将 ViaticosIconList
传递给 remove_item()
,您可以将 bind
调用更改为:
icon.bind(on_press=partial(self.remove_item, add_item))
partial
实质上创建了一个新函数,它将 add_item
作为参数。见 documentation.
然后,您必须调整 remove_item()
方法定义以处理附加参数:
def remove_item(self, instance, icon):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
icon
参数是以前的instance
参数,新参数是instance
(add_item
)。
您可以通过为包含所有通用代码的费用类型创建基础 class 来简化您的 classes,然后每个不同的费用类型都可以扩展该基础 class .
我目前正在构建一个用作差旅费用管理器的应用程序。我有一个系统,其中用户在 MDTextField 上写入所需的费用金额,此类费用将记录在 MDList 中,请求的费用总额将添加到 MDTextField。为清楚起见,我将 post 截图:
到目前为止,所有系统都可以正常工作。但是,用户可能会犯错误。我希望用户能够在按下垃圾桶图标时从 MDList 中删除一个项目。同时,应从请求的总金额中减去已删除的支出金额。 (即,如果用户删除了 Alimentación 中包含 $1,000.00 的元素,则删除后请求的总金额应为 $2000.0)。
在我的代码中,我已经能够将图标的 on_pressed 事件绑定到 remove_item 函数。成功完成所需的减法,之后将显示成功 toast。然而,这是在没有实际从 MDList 中删除项目的情况下完成的。如第二张截图所示,总费用金额为0,但MDList项并没有被删除(remove_widget函数在我的remove_item函数中没有做所需的操作)。
最小可重现示例代码:
Python代码:
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
from kivymd.uix.list import TwoLineIconListItem, IconLeftWidget
from kivymd.toast import toast
class ViaticosIconList(TwoLineIconListItem):
pass
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
elif self.ids.monto_aliment_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
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()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Alimentación Personal", secondary_text=self.ids.monto_aliment_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_aliment_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_aliment_viaje.text = ''
def show_toast(self):
toast("Monto de Alimentación Personal eliminado de la solicitud")
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]
def sumar_gasto(self):
if self.ids.monto_casetas_viaje.text == "":
pass
elif self.ids.monto_casetas_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_casetas_viaje.text)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.apply_currency_format()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Casetas", secondary_text=self.ids.monto_casetas_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_casetas_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_casetas_viaje.text = ''
def show_toast(self):
toast("Monto de Casetas eliminado de la solicitud")
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]
def sumar_gasto(self):
if self.ids.monto_gas_viaje.text == "":
pass
elif self.ids.monto_gas_viaje.text.startswith('$'):
pass
else:
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
monto_total += float(self.ids.monto_gas_viaje.text)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.apply_currency_format()
screen_list_view = MDApp.get_running_app().root.get_screen('travelManager').ids.viaticos_list
icon = IconLeftWidget(icon='delete')
add_item = ViaticosIconList(text=f"Gasolina", secondary_text=self.ids.monto_gas_viaje.text)
add_item.add_widget(icon)
icon.bind(on_press=self.remove_item)
screen_list_view.add_widget(add_item)
def remove_item(self, instance):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
def substract_expense(self):
travel_manager = MDApp.get_running_app().root.get_screen('travelManager')
monto_total = float(travel_manager.ids.suma_solic_viaje.text[2:])
substract_amount = self.ids.monto_gas_viaje.text[1:-3].replace(',', '')
monto_total -= float(substract_amount)
travel_manager.ids.suma_solic_viaje.text = "$ " + str(monto_total)
self.ids.monto_gas_viaje.text = ''
def show_toast(self):
toast("Monto de Gasolina eliminado de la solicitud")
class LoginWindow(Screen):
pass
class TravelManagerWindow(Screen):
panel_container = ObjectProperty(None)
# EXPANSION PANEL PARA SOLICITAR GV
def set_expansion_panel(self):
self.ids.panel_container.clear_widgets()
# 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")))
### WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
class ReprodExample(MDApp):
def build(self):
self.theme_cls.primary_palette = "Teal"
return WindowManager()
if __name__ == "__main__":
ReprodExample().run()
KV 文件:
<WindowManager>:
LoginWindow:
TravelManagerWindow:
<LoginWindow>:
name: 'login'
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()
MDRaisedButton:
text: 'Back'
pos_hint: {'center_x': 0.5, 'center_y': 0.85}
size_hint: None, None
on_release:
root.manager.transition.direction = 'down'
root.manager.current = 'login'
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", "350dp"
pos_hint: {"top": 0.9, "center_x": .5}
elevation: 0.1
BoxLayout:
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"
MDBoxLayout:
padding: '5dp', '10dp', '5dp', '10dp'
MDList:
pos_hint: {'x': 0, 'top': 1}
id: viaticos_list
padding: 0
<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
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.sumar_gasto()
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
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.sumar_gasto()
BoxLayout:
size_hint_x: 0.05
最后,如果您能给我 Python 文件的代码优化建议,我将不胜感激。我在我的 类 中重复基本相同的代码,只是指的是不同的小部件。我可以列出我想与之交互的小部件并进行循环,得到相同的结果吗?我是 Python 的新手,所以我想我需要学习更好的编码方法。
提前致谢。
问题是您的 remove_item()
试图删除错误的对象。传递给 remove_item()
的 instance
是图标,而不是 ViaticosIconList
。为了将 ViaticosIconList
传递给 remove_item()
,您可以将 bind
调用更改为:
icon.bind(on_press=partial(self.remove_item, add_item))
partial
实质上创建了一个新函数,它将 add_item
作为参数。见 documentation.
然后,您必须调整 remove_item()
方法定义以处理附加参数:
def remove_item(self, instance, icon):
# Remove item once the trash icon is clicked (pendiente)
travel = MDApp.get_running_app().root.get_screen('travelManager')
travel.ids.viaticos_list.remove_widget(instance)
self.substract_expense()
self.show_toast()
icon
参数是以前的instance
参数,新参数是instance
(add_item
)。
您可以通过为包含所有通用代码的费用类型创建基础 class 来简化您的 classes,然后每个不同的费用类型都可以扩展该基础 class .