Reputation: 1
I have two main files.py and demo.kv. When executing the add_item function, I add 4 widgets (Label - 3 and MDRaisedButton - 1) and they form a string.
I want some way to press the 'delete this' button in a row to delete that particular row. I imagine I'd need some way to differentiate between these generated rows somehow but I haven't gotten that figured out yet either. I'd be extatic if someone had an elegant solution for this, as I've been stuck here for quite some time.
main.py
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDRaisedButton
Window.size = (500, 600)
finalPrice = []
finalItems = []
finalCounter = []
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = 'Blue'
return Builder.load_file('demo.kv')
def add_item(self, name, price, counter):
mdRB = MDRaisedButton(text='delete this')
mdRB.bind(on_press=self.delete_mdRB)
self.root.ids.basketItems.add_widget(
MDLabel(text=name, adaptive_height=True, adaptive_width=True)
)
self.root.ids.basketItems.add_widget(
MDLabel(text=price, adaptive_height=True, adaptive_width=True, width=60, size_hint_x=None)
)
self.root.ids.basketItems.add_widget(
MDLabel(text=counter, adaptive_height=True, adaptive_width=True, width=120, size_hint_x=None)
)
self.root.ids.basketItems.add_widget(
mdRB
)
def delete_mdRB(self):
for child in [child for child in self.root.ids.basketItems.children]:
self.root.ids.basketItems.remove_widget(child)
finalPrice.clear()
print(finalPrice)
finalItems.clear()
print(finalItems)
finalCounter.clear()
print(finalCounter)
if __name__ == '__main__':
MainApp().run()
demo.kv
#:import Factory kivy.factory.Factory
<Bases@Popup>
auto_dismiss: True
title: 'Item'
background_normal: ""
background_color: (26/255, 149/255, 184/255, .9)
ScrollView:
size: self.size
GridLayout:
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
cols: 3
size: root.width * 0.5, root.height * 0.5
row_default_height: 35
row_force_default: True
center: root.width / 1, root.height / 1
Label:
text: ''
Label:
text: ''
Button:
text: 'Close'
font_size: 12
on_release: root.dismiss()
Label:
text: 'Name'
font_size: 12
text_size: self.size
halign: 'left'
valign: 'middle'
Label:
text: 'Кол-во'
font_size: 12
text_size: self.size
halign: 'right'
valign: 'middle'
Label:
text: 'Basket'
font_size: 12
Label:
text: f'Item 1 290$'
font_size: 12
text_size: self.size
halign: 'left'
valign: 'middle'
AnchorLayout:
anchor_x: 'right'
TextInput:
id: name_input
multiline: 'False'
width: 60
size_hint_x: None
Button:
text: '+'
on_press:
app.add_item('Item 1', '290', name_input.text)
Label:
text: f'Item 2 250$'
font_size: 12
text_size: self.size
halign: 'left'
valign: 'middle'
AnchorLayout:
anchor_x: 'right'
TextInput:
id: name_input2
multiline: 'False'
width: 60
size_hint_x: None
Button:
text: '+'
on_press:
app.add_item('Item 2', '250', name_input2.text)
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Store'
MDBottomNavigation:
MDBottomNavigationItem:
name: 'Items'
text: 'Main'
icon: 'home'
MDBoxLayout:
orientation: 'vertical'
pos_hint: {'center_y':0.5}
adaptive_height: True
spacing: 2
MDRaisedButton:
text: 'Items'
pos_hint: {"center_x":.5}
width: dp(250) + (self.ids.lbl_txt.texture_size[0] - self.ids.lbl_txt.texture_size[0])
on_release: Factory.Bases().open()
MDBottomNavigationItem:
name: 'Basket'
text: 'Basket'
icon: 'basket'
ScrollView:
size: self.size
GridLayout:
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
size: root.width * 0.5, root.height * 0.5
row_default_height: 35
row_force_default: True
center: root.width / 1, root.height / 1
id: basketItems
cols: 4
spacing: 4
Upvotes: 0
Views: 40
Reputation: 38822
A Convenient way to do this is to put everything that you want to delete at one time into a single widget, so you can just delete that single widget. In your case, that single widget can be a BoxLayout
that contains your three Labels
and the Button
. Then by using another BoxLayout
instead of a GridLayout
inside the ScrollView
, each row can become a single BoxLayout
. So changing the kv to use a BoxLayout
:
MDBottomNavigationItem:
name: 'Basket'
text: 'Basket'
icon: 'basket'
ScrollView:
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
center: root.width / 1, root.height / 1
id: basketItems
spacing: 4
Then, the add_item()
method can just add a BoxLayout
to the basket and the delete_mdRB()
can just delete that BoxLayout
:
def add_item(self, name, price, counter):
box = MDBoxLayout(adaptive_height=True)
mdRB = MDRaisedButton(text='delete this')
mdRB.bind(on_press=partial(self.delete_mdRB, box)) # pass the box to be removed
box.add_widget(
MDLabel(text=name, adaptive_height=True, adaptive_width=True)
)
box.add_widget(
MDLabel(text=price, adaptive_height=True, adaptive_width=True, width=60, size_hint_x=None)
)
box.add_widget(
MDLabel(text=counter, adaptive_height=True, adaptive_width=True, width=120, size_hint_x=None)
)
box.add_widget(
mdRB
)
self.root.ids.basketItems.add_widget(
box
)
def delete_mdRB(self, box, button):
box.parent.remove_widget(box)
# for child in [child for child in self.root.ids.basketItems.children]:
# self.root.ids.basketItems.remove_widget(child)
finalPrice.clear()
print(finalPrice)
finalItems.clear()
print(finalItems)
finalCounter.clear()
print(finalCounter)
Upvotes: 0