I am trying to make an app that has a stack of rows that you can add to/remove from at the press of buttons.
I have got the 'Add Row' button working well, now I need the 'Remove Row' functionality.
I have the rows in lists '(self.rows.content.children)', I just need to know how to pop the last one from the list, then keep adding/subtracting at will.
Thanks for looking.
test.py
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.properties import ObjectProperty, StringProperty, ListProperty
from kivy.clock import Clock
from sql_update_data import update_db
kivy.require('1.10.1')
class GUILayout(BoxLayout, GridLayout):
rows = ObjectProperty(None)
def add_more(self):
self.ids.rows.add_row()
def remove_row(self):
print("Remove last row")
def insert_value(self):
values = [row.values for row in reversed(self.rows.content.children)]
for category, id, strap in values:
update_db(category, id, strap)
class Row(BoxLayout):
button_text = StringProperty("")
id = ObjectProperty(None)
values = ListProperty()
class Rows(ScrollView):
row_count = 0
content = ObjectProperty(None)
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
Clock.schedule_once(self.add_row)
def add_row(self, *args):
self.row_count += 1
self.content.add_widget(Row(button_text=str(self.row_count),
id=str(self.row_count)))
class TestApp(App):
def build(self):
return GUILayout()
GUIApp = TestApp()
GUIApp.run()
test.kv
#: import main test
<Row>:
values: row_id.text, col1.text, col2.text
orientation: "horizontal"
spacing: 0, 5
size_hint_y: None
height: "60dp"
spacing: 2
pos_hint: {'center_x': .50, 'y': .80}
Button:
id: row_id
text: root.button_text
size_hint_x: .1
Spinner:
id: col1
text: 'Select Category'
values: ['One', 'Two', 'Three']
size_hint_x: .3
TextInput:
id: col2
size_hint_x: .8
<Rows>:
content: content
BoxLayout:
id: content
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
GUILayout:
<GUILayout>:
rows: rows
orientation: "vertical"
padding: 10
spacing: 10
BoxLayout:
orientation: "horizontal"
height: 60
BoxLayout:
orientation: "horizontal"
size_hint_x: .25
TabbedPanel:
do_default_tab: False
# ----------- TAB 1 ------------
TabbedPanelItem:
text: "tab1"
BoxLayout:
orientation: 'vertical'
Rows:
id: rows
GridLayout:
rows: 1
cols: 6
padding: 1
spacing: 5
size_hint_y: None
height: 50
# --------- MINUS ---------
Button:
text: " - "
font_size: 70
size_hint_x: .1
on_press: root.remove_row()
# -------- SUBTRACT -------
Button:
text: " + "
font_size: 50
size_hint_x: .1
on_press: root.add_more()
# ----- UPDATE MAESTRO -----
Button:
text: "Update Maestro"
size_hint_x: .4
on_press: root.insert_value()
# -------- SETTINGS --------
Button:
text: "Settings"
font_size: 30
size_hint_x: .2
What you should do is remove the last child widget from content using the remove_widget method, on the other hand do not use id as the name of a variable since it is a reserved word:
On the other hand GUILayout must not inherit 2 widgets, it is only necessary that it be from BoxLayout.
# ..
class GUILayout(BoxLayout):
rows = ObjectProperty(None)
def add_more(self):
self.rows.add_row()
def remove_row(self):
self.rows.remove_row()
def insert_value(self):
values = [row.values for row in reversed(self.rows.content.children)]
for category, _id, strap in values:
update_db(category, _id, strap)
#...
class Rows(ScrollView):
content = ObjectProperty(None)
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.row_count = 0
Clock.schedule_once(lambda _: self.add_row())
def add_row(self):
self.row_count += 1
self.content.add_widget(Row(button_text=str(self.row_count),
id=str(self.row_count)))
def remove_row(self):
if self.content.children:
self.content.remove_widget(self.content.children[0])
self.row_count -= 1
# ...
Related
Here I have program that calculates profit based on expenses and revenue.
It works just fine as shown in the image. What I'm trying to do is change the text of buttons in the bottom most boxlayout every time the calc() function is triggered in the MyGrid() class. I tried to use id's but I'm doing it wrong. Also I tried using the on_press method in my .kv file but I actually want the button.text to change EVERYTIME the calc() is triggered irrespective of the button being pressed or not.
NOTE: only the MyGrid() class and MyScroll: is worth looking at everything else works as expected
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.metrics import dp
Builder.load_file("sample1.kv")
class MyLayout(BoxLayout):
pass
class HeaderBox(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1,0.1)
self.orientation = "horizontal"
self.headers = ["Name","Price","Quantity","Name","Price","Quantity"]
for i in range(6):
b = Button(text=str(self.headers[i]))
self.add_widget(b)
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 6
self.textinputs=[0] #i put a 0 in that list so that my object indexing can start with 1
#made a diff list full of indexes so i can use them in my calculating algo
self.expense_price_index = [2,8,14,20,26,32,38,44,50,56]
self.expense_quantity_index = [3,9,15,21,27,33,39,45,51,57]
self.revenue_price_index = [5,11,17,23,29,35,41,47,53,59]
self.revenue_quantity_index = [6,12,18,24,30,36,42,48,54,60]
#initializing some values
self.expense_total = 0
self.revenue_total = 0
self.profit = 0
#making a grid full of textinputs and adding them to self.textinputs list
for i in range(60):
b = TextInput(multiline=False,font_size=dp(20),size_hint=(1,None),height=50)
b.bind(on_text_validate=self.calc) #binding a function to make my calculations
self.textinputs.append(b)
self.add_widget(b)
#FUNCTION THAT DOES THE CALCULATIONS
def calc(self,ti_instance):
default_quantity = 1
self.expense_total = 0
self.revenue_total = 0
# CALCULATING EXPENSE TOTAL
for i in self.expense_price_index:
if self.textinputs[i].text == "":
continue
elif self.textinputs[i+1].text == "":
self.expense_total += int(self.textinputs[i].text) * default_quantity
else:
self.expense_total += int(self.textinputs[i].text) * int(self.textinputs[i+1].text)
# CALCULATING REVENUE TOTAL
for i in self.revenue_price_index:
if self.textinputs[i].text == "":
continue
elif self.textinputs[i+1].text == "":
self.revenue_total += int(self.textinputs[i].text) * default_quantity
else:
self.revenue_total += int(self.textinputs[i].text) * int(self.textinputs[i+1].text)
# CALCULATING PROFIT DOING BASIC ARITHMETIC
self.profit = str(self.revenue_total - self.expense_total)
print("Profit: " + self.profit)
class MyScroll(ScrollView):
pass
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyApp().run() ```
```#:import dt datetime.date
#:import dp kivy.metrics.dp
#:set navbar_button_color (59/255, 68/255, 75/255, 1)
<MyLayout>:
orientation: "vertical"
BoxLayout:
size_hint: 1,0.1
Button:
text: "Back"
size_hint: 0.1,1
Button:
text: "Home"
size_hint: 0.1,1
Button:
text: "Daily"
size_hint: 0.1,1
Button:
text: "Weekly"
size_hint: 0.1,1
Button:
text: "Monthly"
size_hint: 0.1,1
Label:
text: dt.today().strftime("%d %B %Y")
size_hint: 0.5,1
canvas.before:
Color:
rgb: 59/255, 78/255, 85/255,1
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint: 1,0.15
Button:
text: "EXPENSES"
Button:
text: "REVENUE"
HeaderBox:
MyScroll:
BoxLayout:
orientation:"horizontal"
size_hint: 1,0.2
BoxLayout:
orientation: "vertical"
Button:
text: "Expense Total:"
font_size: dp(20)
on_press:
self.text: "Expense Total: " + str(my_grid.expense_total)
Button:
text: "Revenue Total:"
font_size: dp(20)
on_press:
self.text: "Revenue Total: " + str(my_grid.revenue_total)
Button:
text: "Profit:"
font_size: dp(40)
on_press:
self.text: "Profit: " + str(my_grid.profit)
<MyScroll>:
my_grid: my_grid
MyGrid:
id: my_grid
size_hint: 1, None
height: self.minimum_height```
#for #ApuCoder
```Button:
id: revenue_button
text: "Revenue Total: "
font_size: dp(20)
on_press:
self.text = "Revenue Total: " + str(my_grid.revenue_total)```
```class MyGrid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
expense_button = ObjectProperty()```
```# CALCULATING PROFIT DOING BASIC ARITHMETIC
self.profit = str(self.revenue_total - self.expense_total)
self.expense_button.text = "Expense Total: " + str(self.expense_total) <-----
print("Profit: " + self.profit) ``````
You can access your MyGrid in python or kvlang by creating a reference. One of the few ways is simply using an id.
With this and other necessary modifications your full code in kvlang looks like,
#:import dt datetime.date
#:import dp kivy.metrics.dp
#:set navbar_button_color (59/255, 68/255, 75/255, 1)
<MyLayout>:
orientation: "vertical"
BoxLayout:
size_hint: 1,0.1
Button:
text: "Back"
size_hint: 0.1,1
Button:
text: "Home"
size_hint: 0.1,1
Button:
text: "Daily"
size_hint: 0.1,1
Button:
text: "Weekly"
size_hint: 0.1,1
Button:
text: "Monthly"
size_hint: 0.1,1
Label:
text: dt.today().strftime("%d %B %Y")
size_hint: 0.5,1
canvas.before:
Color:
rgb: 59/255, 78/255, 85/255,1
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint: 1,0.15
Button:
text: "EXPENSES"
Button:
text: "REVENUE"
HeaderBox:
MyScroll: # Add the grid directly here.
MyGrid:
id: my_grid
size_hint: 1, None
height: self.minimum_height
BoxLayout:
orientation:"horizontal"
size_hint: 1,0.2
BoxLayout:
orientation: "vertical"
Button:
# text: "Expense Total:"
text: "Expense Total: " + str(my_grid.expense_total)
font_size: dp(20)
on_press:
self.text = "Expense Total: " + str(my_grid.expense_total)
Button:
# text: "Revenue Total:"
text: "Revenue Total: " + str(my_grid.revenue_total)
font_size: dp(20)
on_press:
self.text = "Revenue Total: " + str(my_grid.revenue_total)
Button:
# text: "Profit:"
text: "Profit: " + str(my_grid.profit)
font_size: dp(40)
on_press:
self.text = "Profit: " + str(my_grid.profit)
#<MyScroll>:
# my_grid: my_grid
# MyGrid:
# id: my_grid
# size_hint: 1, None
# height: self.minimum_height
Now create some properties for those attributes using NumericProperty in python.
Modified full code in python,
from kivy.uix.textinput import TextInput
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import NumericProperty
Builder.load_file("sample1.kv")
class MyLayout(BoxLayout):
pass
class HeaderBox(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1,0.1)
self.orientation = "horizontal"
self.headers = ["Name","Price","Quantity","Name","Price","Quantity"]
for i in range(6):
b = Button(text=str(self.headers[i]))
self.add_widget(b)
class MyGrid(GridLayout):
expense_total = NumericProperty(0)
profit = NumericProperty(0)
revenue_total = NumericProperty(0)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 6
self.textinputs=[0] #i put a 0 in that list so that my object indexing can start with 1
#made a diff list full of indexes so i can use them in my calculating algo
self.expense_price_index = [2,8,14,20,26,32,38,44,50,56] # range(2, 60, 6)
self.expense_quantity_index = [3,9,15,21,27,33,39,45,51,57] # range(3, 60, 6) etc.
self.revenue_price_index = [5,11,17,23,29,35,41,47,53,59]
self.revenue_quantity_index = [6,12,18,24,30,36,42,48,54,60]
#initializing some values
# self.expense_total = 0
# self.revenue_total = 0
# self.profit = 0
#making a grid full of textinputs and adding them to self.textinputs list
for i in range(60):
b = TextInput(multiline=False,font_size=dp(20),size_hint=(1,None),height=50)
b.bind(on_text_validate=self.calc) # binding a function to make my calculations
# b.bind(text=self.calc) # Bound to the property text.
self.textinputs.append(b)
self.add_widget(b)
#FUNCTION THAT DOES THE CALCULATIONS
def calc(self,ti_instance):
# def calc(self,ti_instance, text): # If bound to the property text.
default_quantity = 1
self.expense_total = 0
self.revenue_total = 0
# CALCULATING EXPENSE TOTAL
for i in self.expense_price_index:
if self.textinputs[i].text == "":
continue
elif self.textinputs[i+1].text == "":
self.expense_total += int(self.textinputs[i].text) * default_quantity
else:
self.expense_total += int(self.textinputs[i].text) * int(self.textinputs[i+1].text)
# CALCULATING REVENUE TOTAL
for i in self.revenue_price_index:
if self.textinputs[i].text == "":
continue
elif self.textinputs[i+1].text == "":
self.revenue_total += int(self.textinputs[i].text) * default_quantity
else:
self.revenue_total += int(self.textinputs[i].text) * int(self.textinputs[i+1].text)
# CALCULATING PROFIT DOING BASIC ARITHMETIC
self.profit = self.revenue_total - self.expense_total
print("Profit: " + str(self.profit))
class MyScroll(ScrollView):
pass
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyApp().run()
In one part of my program I have a RecycleView that uses a RecycleBoxLayout and together they hold a bunch of DownloadItem instances which itself inherits from MDCard.
The problem with the recycleview is that it sorts the items in an absurd way. I would like the items to be shown in the order that they were added, not be sorted by the recycleview.
Example:
RecycleView sorting items
My Python file:
from kivy.lang import Builder
from kivy.properties import StringProperty, ColorProperty
from kivy.animation import Animation
from kivymd.uix.card import MDCard
from kivymd.app import MDApp
class DownloadItem(MDCard):
path = StringProperty()
url_type = StringProperty("file")
def __init__(self, **kwargs):
self.paused = False
self.fill_animation = None
super(DownloadItem, self).__init__(**kwargs)
def pause_resume_download(self):
if not self.paused:
self.ids.pause_resume_button.icon = "play"
if self.fill_animation is not None:
self.fill_animation.cancel(self.ids.progress_bar)
self.paused = True
else:
self.ids.pause_resume_button.icon = "pause"
self.fill_animation = Animation(value=100, duration=4)
self.fill_animation.bind(on_complete=lambda *args: Animation(color=self.theme_cls.accent_color,
duration=Example.color_duration)
.start(self.ids.progress_bar))
self.fill_animation.start(self.ids.progress_bar)
self.paused = False
Animation(color=app.pause_color if self.paused else self.theme_cls.primary_color,
duration=Example.color_duration).start(self.ids.progress_bar)
def cancel_download(self):
if self.fill_animation is not None:
self.fill_animation.cancel(self.ids.progress_bar)
Animation(color=app.fail_color,
duration=Example.color_duration).start(self.ids.progress_bar)
class Example(MDApp):
fail_color = ColorProperty([255 / 255, 99 / 255, 71 / 255, 1.0])
pause_color = ColorProperty([240 / 255, 163 / 255, 10 / 255, 1.0])
success_color = ColorProperty(None)
color_duration = .15
def __init__(self, **kwargs):
global app
super(Example, self).__init__(**kwargs)
self.kv = Builder.load_file("design.kv")
self.path = "C:/Users/Family/Downloads/"
app = self
def build(self):
self.theme_cls.theme_style = "Dark"
return self.kv
def add_item(self):
self.kv.ids.downloads_list.data.append({"path": self.path + '/' if self.path[-1] != '/' else self.path,
"url_type": "file"})
if __name__ == '__main__':
Example().run()
My KV file:
#:kivy 2.0.0
<TooltipMDLabel#MDLabel+MDTooltip>
<DownloadItem>:
orientation: "vertical"
padding: 10
spacing: 10
size_hint_y: None
height: 100
elevation: 20
border_radius: 5
radius: [5]
MDBoxLayout:
adaptive_height: True
spacing: 5
MDIcon:
icon: root.url_type
size_hint_x: None
width: self.texture_size[0]
TooltipMDLabel:
text: root.path if len(root.path) <= 30 else root.path[:31] + " ..."
tooltip_text: f"Path: {root.path}\nType: {root.url_type}"
tooltip_bg_color: app.theme_cls.bg_darkest
tooltip_text_color: app.theme_cls.opposite_bg_darkest
size_hint_y: None
height: self.texture_size[1]
MDSeparator:
MDBoxLayout:
spacing: 10
MDProgressBar:
id: progress_bar
min: 0
max: 100
value: 50
color: app.theme_cls.primary_color
MDIconButton:
id: pause_resume_button
icon: "pause"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: root.pause_resume_download()
MDIconButton:
icon: "close"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: root.cancel_download()
BoxLayout:
orientation: "vertical"
spacing: 10
RecycleView:
id: downloads_list
viewclass: "DownloadItem"
RecycleBoxLayout:
default_size: None, 100
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
padding: 15
spacing: 15
MDRaisedButton:
text: "Add"
size_hint_x: 1
on_release: app.add_item()
The RecycleView does not sort the items. They are presented in the order that they appear in the data. What you are seeing is the "recycle" behavior, where your DownloadItems are recycled, making it appear that they are sorted. Try adding a count number to the display of each DownloadItem, and you will see more clearly what is happening.
I've created a responsive list of widgets, but every new item is added at the bottom. I read the documentation, looked for information on the Internet, but I did not find anything, my last hope is you)
It looks like this:
v
v
v
|
|
|Element 5
|
|Element 6
|
|Element 7
|
v
v
v
And I want each new element to be created on top of the others.
That is, like this:
^
^
^
|
|
|Element 7
|
|Element 6
|
|Element 5
|
|Element 4
|
|Element 3
|
|Element 2
|
^
^
^
in short, I need everything the same but in reverse.
HERE IS MY CODE:
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 400)
Builder.load_string('''
<Button#Button>:
font_size: 15
font_name: 'Verdana'
<Label#Label>:
font_size: 15
font_name: 'Verdana'
<TextInput#TextInput>:
font_size: 15
font_name: 'Verdana'
padding_y: 3
<Row>:
size_hint_y: None
height: self.minimum_height
height: 40
Button:
text: root.button_text
size_hint_x: None
top: 200
Button:
text: 'World 1'
width: 300
<Rows>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<User>:
BoxLayout:
orientation: "vertical"
padding : 20, 5
BoxLayout:
orientation: "horizontal"
#padding : 10, 10
spacing: 10, 10
size: 450, 40
size_hint: None, None
Label:
size_hint_x: .2
text: "Test 1"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .8
text: "Test 2"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
size_hint_x: .2
size_hint_y: .2
Button:
text: "+Add More"
on_press: root.add_more()
BoxLayout:
orientation: "horizontal"
padding : 10, 5
spacing: 10, 10
size_hint: .5, .35
pos_hint: {'x': .25, 'y':.25}
Button:
text: 'Ok'
Button:
text: 'Cancel'
''')
class User(Screen):
def add_more(self):
self.ids.rows.add_row()
class Row(BoxLayout):
button_text = StringProperty("")
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_row()
def add_row(self):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
class Test(App):
def build(self):
self.root = Builder.load_file('Demo.kv')
return self.root
if __name__ == '__main__':
Test().run()
The add_widget() method allows for an index argument that indicates where in the list of children that the new widget should be placed. See the documentation. So you can just use tht index argument to do what you want:
self.add_widget(Row(button_text=str(self.row_count)), index=self.row_count-1)
I am new to python and kivy.
I am trying to get value of dynamic row.But now i am getting value like this
Column2
Column1
Can someone tell me how to get value like this ?
1,column1,column2
2,column1,column2
Because i have three column in my database table like id,name,value and i want to insert value in database table through loop
I am using this code
def insert_value(self):
values = []
rows = self.ids.rows
for row in reversed(rows.children):
for ch in row.children:
if isinstance(ch, TextInput):
values.append(ch.text)
lenArray = len(values)
for x in range(0, lenArray):
print (values[x])
demo.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.uix.textinput import TextInput
Window.size = (450, 525)
class display(Screen):
def add_more(self):
self.ids.rows.add_row()
def insert_value(self):
values = []
rows = self.ids.rows
for row in reversed(rows.children):
for ch in row.children:
if isinstance(ch, TextInput):
values.append(ch.text)
lenArray = len(values)
for x in range(0, lenArray):
print (values[x])
class Row(BoxLayout):
button_text = StringProperty("")
id = ObjectProperty(None)
class Rows(BoxLayout):
orientation = "vertical"
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_row()
def add_row(self):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count),id=str("test"+str(self.row_count))))
class test(App):
def build(self):
self.root = Builder.load_file('demo.kv')
return self.root
if __name__ == '__main__':
test().run()
demo.kv
<Row>:
orientation: "horizontal"
spacing: 0, 5
Button:
text: root.button_text
size_hint_x: .2
TextInput:
text:"Column1"
size_hint_x: .8
TextInput:
text:"Column2"
size_hint_x: .8
display:
BoxLayout:
orientation: "vertical"
padding : 20, 20
BoxLayout:
orientation: "horizontal"
Button:
size_hint_x: .2
text: "+Add More"
valign: 'bottom'
on_press: root.add_more()
BoxLayout:
orientation: "horizontal"
Label:
size_hint_x: .2
text: "SN"
valign: 'bottom'
Label:
size_hint_x: .8
text: "Value"
valign: 'bottom'
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
padding : 10, 0
spacing: 10, 10
size_hint: .5, .7
pos_hint: {'x': .25, 'y':.25}
Button:
text: 'Ok'
on_release:
root.insert_value()
Button:
text: 'Cancel'
on_release: root.dismiss()
To maintain a structure we must create a list of lists, then in each list the first parameter is the text of the Button that we filter through isinstance(), and the other elements are concatenated.
[...]
from kivy.uix.button import Button
class display(Screen):
def add_more(self):
self.ids.rows.add_row()
def insert_value(self):
values = []
rows = self.ids.rows
for row in reversed(rows.children):
vals = []
for ch in reversed(row.children):
if isinstance(ch, TextInput):
vals.append(ch.text)
if isinstance(ch, Button):
vals.insert(0, ch.text)
values.append(vals)
for val in values:
print("{},{},{}".format(*val))
[...]
One option is to add a ListProperty to your Row class that stores the values of the row in the order you want, which makes it easier to obtain them later.
You can use a ListView to show the rows.
Demo.kv:
<Row>:
values: row_id.text, col1.text, col2.text
orientation: "horizontal"
spacing: 0, 5
size_hint_y: None
height: 30
Button:
id: row_id
text: root.button_text
size_hint_x: .2
TextInput:
id: col1
text:"Column1"
size_hint_x: .8
TextInput:
id: col2
text:"Column2"
size_hint_x: .8
<Rows>:
content: content
BoxLayout:
id: content
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
Display:
rows: rows
BoxLayout:
orientation: "vertical"
padding : 20, 20
BoxLayout:
orientation: "horizontal"
Button:
size_hint_x: .2
text: "+Add More"
valign: 'bottom'
on_press: root.add_more()
BoxLayout:
orientation: "horizontal"
Label:
size_hint_x: .2
text: "SN"
valign: 'bottom'
Label:
size_hint_x: .8
text: "Value"
valign: 'bottom'
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
padding : 10, 10
spacing: 10, 10
size_hint: .5, .7
pos_hint: {'x': .25, 'y':.25}
Button:
text: 'Ok'
on_release:
root.insert_value()
Button:
text: 'Cancel'
on_release: root.dismiss()
Demo.py:
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, StringProperty, ObjectProperty
from kivy.uix.scrollview import ScrollView
from kivy.clock import Clock
Window.size = (450, 525)
class Display(Screen):
rows = ObjectProperty(None)
def __init__(self, **kwargs):
super(Display, self).__init__(**kwargs)
def add_more(self):
self.rows.add_row()
def insert_value(self):
values = [row.values for row in reversed(self.rows.content.children)]
for row in values:
print(row)
class Row(BoxLayout):
button_text = StringProperty("")
id = ObjectProperty(None)
values = ListProperty()
class Rows(ScrollView):
row_count = 0
content = ObjectProperty(None)
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
Clock.schedule_once(self.add_row)
def add_row(self, *args):
self.row_count += 1
self.content.add_widget(Row(button_text=str(self.row_count),
id="test" + str(self.row_count)))
class Test(App):
def build(self):
self.root = Builder.load_file('Demo.kv')
return self.root
if __name__ == '__main__':
Test().run()
I have two file demo.py and demo.kv.
When i run demo.py and click on +Add then screen shows looks like.I want value of name textbox in def add_row(self): function when click on button.When i click on button of first row then i want to get test1 in def add_row(self): which are in class RowsExtra(BoxLayout): and click on button of second row then get test2.I want to get test1 value in textName variable.After that i am fetching data from database according name textbox value.
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
textName = 'test1'
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
demo.py
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.uix.popup import Popup
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 400)
class User(Popup):
total_value = ObjectProperty(None)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
def add_more(self):
self.ids.rows.add_more()
class ExtraPopup(Popup):
mode = StringProperty("")
def __init__(self, obj, **kwargs):
super(ExtraPopup, self).__init__(**kwargs)
def add_extra(self):
self.ids.rowsExtra.add_row()
class RowExtra(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?", "?", "?", "?"])
button_text = StringProperty("")
mode = StringProperty("")
def __init__(self, **kwargs):
super(RowExtra, self).__init__(**kwargs)
self.col_data[0] = ''
self.col_data[1] = ''
self.col_data[2] = ''
class RowsExtra(BoxLayout):
#orientation = "vertical"
row_count = 0
button_text = StringProperty("")
def __init__(self, **kwargs):
super(RowsExtra, self).__init__(**kwargs)
self.add_row()
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
textName = 'test1'
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
name = ObjectProperty(None)
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
def add_seller_expenses(self):
self.mode = "Add"
popup = ExtraPopup(self)
popup.open()
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_more()
def add_more(self):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
class rv(BoxLayout):
data_items = ListProperty([])
mode = StringProperty("")
def __init__(self, **kwargs):
super(rv, self).__init__(**kwargs)
def add(self):
self.mode = "Add"
popup = User()
popup.open()
class MainMenu(BoxLayout):
content_area = ObjectProperty()
def display(self):
self.rv = rv()
self.content_area.add_widget(self.rv)
class demo(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
demo().run()
demo.kv
<Row>:
size_hint_y: None
height: self.minimum_height
height: 40
Button:
text: root.button_text
size_hint_x: None
top: 200
TextInput:
id : name
text: root.col_data3
width: 300
TextInput:
id: number_input
text: root.col_data4
width: 300
input_filter: 'int'
Button:
text: "Button"
size_hint_x: None
top: 200
on_press: root.add_seller_expenses()
<Rows>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<User>:
id: user
BoxLayout:
orientation: "vertical"
padding : 20, 5
BoxLayout:
orientation: "horizontal"
#padding : 10, 10
spacing: 10, 10
size: 450, 40
size_hint: None, None
Label:
size_hint_x: .2
text: "Number"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "name"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "Value"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
size_hint_x: .2
size_hint_y: .2
Button:
text: "+Add More"
on_press: root.add_more()
<rv>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: .25, .03
text: "+Add"
on_press: root.add()
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
BoxLayout:
orientation: "vertical"
<ExtraPopup>:
title: " Extra"
title_size: 20
title_font: "Verdana"
size_hint: None, None
size: 400, 400
auto_dismiss: False
BoxLayout:
orientation: "vertical"
padding : 10, 5
spacing: 10, 10
BoxLayout:
orientation: "horizontal"
spacing: 10, 10
size: 550, 30
size_hint: 1, None
Label:
size_hint_x: .3
text: "SN"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .7
text: "Name"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
RowsExtra:
id: rowsExtra
BoxLayout:
orientation: "horizontal"
size_hint_x: .3
size_hint: .15, .1
Button:
#size_hint_x: .2
text: "+Add More"
valign: 'bottom'
on_press: root.add_extra()
BoxLayout:
orientation: "horizontal"
padding : 10, 5
spacing: 10, 10
size_hint: .5, .2
pos_hint: {'x': .25, 'y':.25}
Button:
text: 'Ok'
id: ok_text
on_release:
root.dismiss()
Button:
text: 'Cancel'
#size_hint_x: .5
on_release: root.dismiss()
<RowExtra>:
size_hint_y: None
height: self.minimum_height
height: 30
Button:
text: root.button_text
size_hint_x: .3
#top: 200
TextInput:
text: root.col_data[1]
size_hint_x: .7
<RowsExtra>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (100, 40)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
content_area: content_area
BoxLayout:
orientation: 'vertical'
spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 2
MenuButton:
text: 'Menu'
size : (50, 12)
on_release: root.display()
BoxLayout:
id: content_area
size_hint_y: 30
A possible solution is to access rowsExtra through the popup since it is your child, but one problem is that you call add_row() in the constructor before it is assigned a parent (the assignment of a parent is after the creation of the object), we must eliminate that instruction and call it again before opening the popup. To store the text we can create a property of type StringProperty.
[...]
class RowsExtra(BoxLayout):
#orientation = "vertical"
row_count = 0
button_text = StringProperty("")
textName = StringProperty("")
def __init__(self, **kwargs):
super(RowsExtra, self).__init__(**kwargs)
def add_row(self):
print("here,i want value of name(`test1`) when click on button")
print(self.textName)
#cur.execute("SELECT `column_name` FROM `table_name` WHERE `name`=?", (textName,))
#rows = cur.fetchone()
rows = [('A1'), ('B1'), ('C1'), ('D1')]
for row in rows:
self.row_count += 1
r = RowExtra(button_text=str(self.row_count))
r.col_data[1] = row
self.add_widget(r)
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
name = ObjectProperty(None)
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
def add_seller_expenses(self):
self.mode = "Add"
popup = ExtraPopup(self)
popup.ids.rowsExtra.textName = self.ids.name.text
popup.ids.rowsExtra.add_row()
popup.open()
[...]