Call def from one class to another class in python - python

I have two file demo.py and demo.kv.
Can anyone tell me how to call function from one class to another class?I want to call def calculate(self): from def on_text(self, text_input, value):.Now i am using code
def on_text(self, text_input, value):
App.get_running_app().User.calculate()
But it gives error AttributeError: 'Test' object has no attribute 'User'
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 add_more(self):
self.ids.rows.add_row()
def calculate(self):
rows = self.ids.rows
total = 0
for row in rows.children:
text = row.ids.number_input.text
total += int(text) if text != "" else 0 # validate if the entry is not empty
self.total_value.text = str(total)
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
self.ids.number_input.bind(text=self.on_text)
def on_text(self, text_input, value):
print('Calling')
App.get_running_app().User.calculate()
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 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 Test(App):
def build(self):
self.root = Builder.load_file('demo.kv')
return MainMenu()
if __name__ == '__main__':
Test().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:
text: root.col_data3
width: 300
TextInput:
id: number_input
text: root.col_data4
width: 300
input_filter: 'int'
<Rows>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<User>:
id: user
total_value:total_value
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"
padding : 10, 5
spacing: 10, 10
size: 200, 40
size_hint: None, None
Label:
size_hint_x: .7
text: "Total value"
TextInput:
id: total_value
on_focus:root.test()
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"
<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

One way to solve this problem without accessing the tree of kivy hierarchies is using global variables, but it is advisable not to abuse this type of variables since the errors generated by its misuse are difficult to trace.
[...]
class Row(BoxLayout):
[...]
def on_text(self, text_input, value):
print('Calling')
popup.calculate()
class rv(BoxLayout):
[...]
def add(self):
self.mode = "Add"
global popup
popup = User()
popup.open()
[...]

This may be a duplicate of this question: Im New on kivy Python classes
Firstly:
class Test(App):
def build(self):
self.root = Builder.load_file('demo.kv')
return MainMenu()
This is a bit unnecessary, you can instead do:
class demo(App):
def build(self):
return MainMenu()
App's search for a kv file with a lowercase name equal to the App's name.
Secondly:
<User>:
id: user
total_value:total_value
This is not how you use ids in the kivy Widgets. When you define a Kivy Widget, ie:
class KivyWidgetName(KivyLayout):
pass
<KivyWidgetName>:
You're creating a class. When you add your custom widget to a parent Widget, you are creating an Object of that KivyWidget Class. Sometimes however if you're making more than one, you need to give them ids so their parent can separate them from each other.
ie:
<RootWidget>:
KivyWidgetName:
id: first_instance
KivyWidgetName:
id: second_instance
So now RootWidget can access two different versions of the class, if it wants to access the first one, it can do:
self.ids.first_instance
You can also access them by the index number in which they appear, so this
can also be done by:
self.ids[1]
However explicit is typically better than implicit
Thirdly, you had the right idea to this:
App.get_running_app().User.calculate()
but it should actually be something like this:
App.get_running_app().root.ids.[INSERTID]
So in this case, you're getting the root widget of app (which is ), then you need to use the ids to get to the proper address.
For example, take this:
:
User:
id: 'user_one'
User:
id: 'user_two'
To access the user calculate function, you can do this:
App.get_running_app().root.ids.user_one.calculate
If you however have a number of children, you'll have to seek all of their ids until you find user:
For example:
<TestWidget>:
User:
id: 'user_one'
User:
id: 'user_two'
<RootWidget>:
TestWidget:
id: 'test_one'
TestWidget:
id: 'test_two'
So to get to user one of test two, you can do this:
App.get_running_app().root.ids.test_two.ids.user_one.calculate
You might need to re-arrange your rootwidget to be something else that just contains your main menu to help you with this but that decision is up to you ultimately.

Related

Manually updating Kivy RecycleView in Python

RecycleView isn't updating its table when data is changed from outside the RecycleView class. As a summary I'm trying to create a simple stock portfolio manager.
I have a custom RecycleView class which I call RecycleViewPortfolio that inherits from RecycleView. From my .kv file I have three buttons connected to functions populate_1, populate_2 and populate_3 within my RecycleViewPortfolio class. Whenever I press a button and call any of the populate functions, the RecycleView behaves as expected.
However whenever I change the RecycleView data from outside the RecycleViewPortfolio class the table doesn't update. For example I have setup a global variable which I have imported to both my .py file and .kv file. I would like to be able to update the table whenever this data in this global variable is changed.
I have tried looking at the documentation from Kivy which mentions different functions that are suppose to solve this issue. But I guess Im clueless to how to apply these methods.
import StackOverflow.globalvariables as GlobalVariables
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty
class AddPopup(Popup):
"""Popup for adding asset"""
asset_name = ObjectProperty
asset_price = ObjectProperty
asset_amount = ObjectProperty
currency = ObjectProperty
asset_class = ObjectProperty
wrapped_button = ObjectProperty()
def __init__(self, *args, **kwargs):
super(AddPopup, self).__init__(*args, **kwargs)
def open(self, correct=True):
super(AddPopup, self).open(correct)
def save_asset(self):
# Make sure no input is empty
if self.asset_name.text.strip() and self.asset_price.text.strip()\
and self.asset_amount.text.strip() and self.currency.text.strip()\
and self.asset_class.text.strip():
GlobalVariables.rv_data_global = [{'text': self.asset_name.text.strip()},
{'text': self.asset_amount.text.strip()},
{'text': self.asset_price.text.strip()}]
self.dismiss()
class RecycleViewPortfolio(RecycleView):
def __init__(self, **kwargs):
super(RecycleViewPortfolio, self).__init__(**kwargs)
self.populate_2()
def populate_1(self):
root = App.get_running_app().root
root.add_popup.open(True)
self.data = GlobalVariables.rv_data_global
def populate_2(self):
self.data = [{'text': str(x)} for x in range(0, 6)]
def populate_3(self):
self.data = [{'text': str(x)} for x in range(6, 12)]
class PortfolioRoot(GridLayout):
"""root to all screens"""
add_popup = ObjectProperty(None)
list = ListProperty([])
def __init__(self, **kwargs):
super(PortfolioRoot, self).__init__(**kwargs)
self.add_popup = AddPopup()
def test_set_data(self):
GlobalVariables.rv_data_global = [{'text': str(x)} for x in range(12, 18)]
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, # View Behavior
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button): # Data Behavior
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(True)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
class PortfolioApp(App):
"""App object"""
def __init__(self, **kwargs):
super(PortfolioApp, self).__init__(**kwargs)
def build(self):
return PortfolioRoot()
PortfolioApp().run()
.kv file
#:kivy 1.10.0
#:import GlobalVariables StackOverflow.globalvariables
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (0, 0.517, 0.705, 1) if self.selected else (0, 0.517, 0.705, 1)
Rectangle:
pos: self.pos
size: self.size
background_color: [1, 0, 0, 1] if self.selected else [1, 1, 1, 1] # dark red else dark grey
on_release:
print("Pressed")
<WrappedLabel#Label>:
size_hint_y: None
height: self.texture_size[1] + (self.texture_size[1]/2)
markup: True
<RecycleViewPortfolio#RecycleView>:
viewclass: 'SelectableButton'
target_id: None
# id: rv_data_list
data: GlobalVariables.rv_data_global
SelectableRecycleGridLayout:
cols: 3
key_selection: 'selectable'
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
<PortfolioRoot>:
BoxLayout:
list: rv_data_list
size: root.size
orientation: 'vertical'
WrappedLabel:
text: "[b] Portfolio Manager [/b]"
font_size: min(root.height, root.width) / 10
GridLayout:
size_hint_y: None
height: root.height * 0.1
cols: 4
rows: 1
# Settings
padding: root.width * 0.001, root.height * 0.001
spacing: min(root.width, root.height) * 0.001
Button:
text: "Add"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_1()
print("Add")
Button:
text: "Change"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_2()
print("Change")
Button:
text: "Remove"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_3()
print("Remove")
Button:
text: "Test"
background_color: [1, 1, 1, 1]
on_release:
root.test_set_data()
print("Test set data")
RecycleViewPortfolio:
id: rv_data_list
<AddPopup>:
size_hint: 0.8, 0.8
title: "Add Asset"
title_size: root.height * 0.05
auto_dismiss: False
asset_name: asset_name
asset_price: asset_price
asset_amount: asset_amount
currency: currency
asset_class:asset_class
wrapped_button: wrapped_button
BoxLayout:
orientation: 'vertical'
GridLayout:
rows: 5
cols: 2
padding: root.width * 0.02, root.height * 0.02
spacing: min(root.width, root.height) * 0.02
Label:
id: asset_name_label
text: "Asset name"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_name
text: "Asset name"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_price_label
text: "Asset price"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_price
text: "asset"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_amount_label
text: "Asset amount"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_amount
text: "Asset amount"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: currency_label
text: "Asset currency"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: currency
text: "currency"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_class_label
text: "Asset class"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_class
text: "Asset class"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Button:
id: wrapped_button
text: "Save"
size_hint: 1, None
height: root.height / 8
on_release: root.save_asset()
Button:
id: wrapped_button
text: "close"
size_hint: 1, None
height: root.height / 8
on_release: root.dismiss()
globalvariables.py
# global variables
rv_data_global = []
I expect to be able to create a popup window where I add information which is stored in a global variable and after changes are made I call for the RecycleView to be updated.
Edit: Added a working example
This example shows how Im able to use the buttons "Change" and "Remove" in order to populate the RecycleView as expected. However when the add button is pressed and the popup window appears and the save button is pressed the RecycleView doesn't update. If the add button is pressed again and directly closed the RecyleView gets updated and shows the correct information.
The same goes for the "Test" buttons where I call a function which changes the global variable. From there I have no idea of how to update the view since Im no longer working underneath the RecycleView class.
TLDR;
Method for manually updating the RecycleView after data has been changed.
I found the answers to one of my questions. By adding:
self.ids.rv_data_list.data = GlobalVariables.rv_data_global
self.ids.rv_data_list.refresh_from_data()
to the test_set_data function, I am now able to refresh the data as I requested. Hence the magic was the refresh_from_data() method.
Through the App.get_running_app() I was able to access the refresh_from_data() command from the popup class.
root = App.get_running_app().root
root.ids.rv_data_list.data = GlobalVariables.rv_data_global
root.ids.rv_data_list.refresh_from_data()
I seem to have solved my own issues here. But if anyone has a better or cleaner solution, please let me know.

Kivy: Updating a field on a ScreenManager screen from a RecycleView

I am struggling with referring to Labels on ScreenManager screens. I have a RecycleView and the class accumulates a total in the init. I would like to put this total on the screen outside the RecycleView. The id in the .kv file is t_pay. The total is accumulated in the Nq_rv class as self.total_bill. How do I take the total from this class and update the total field on the pay screen?
Note the total field at the bottom of this screenshot:
My main.py file is:
class Nq_rv(RecycleView):
def __init__(self, **kwargs):
super(Nq_rv, self).__init__(**kwargs)
bill_text = []
self.total_bill = 0.0
with open('bill.csv') as bill:
bill_reader = csv.reader(bill)
for row in bill_reader:
for item in range(len(row)):
if item < 2:
item_text = row[item]
else:
item_text = '{0:.2f}'.format(float(row[2]))
self.total_bill += float(row[2]) #total accumulation
text_row = {'text': item_text}
bill_text.append(text_row)
self.data = bill_text
#How do I update the t-pay field in the .kv file?
class Sm(ScreenManager):
total_pay = ObjectProperty() #I don't know if this is needed
def send_survey(self):
mypopup = MyPopup()
mypopup.show_popup('Survey', 'Survey sent!', 'OK!')
def pay(self):
mypopup = MyPopup()
mypopup.show_popup('Pay', 'Please put your card in the card reader and follow the prompts.', 'OK!')
def tip_slider_update(self):
self.ids.pay_screen.tip.text = '{0:.2f}'.format(float(self.ids.pay_screen.total_pay.text) * self.ids.pay_screen.tip_sldr.value)
def close_app(self):
App.get_running_app().stop()
class Pay_screen(Screen):
pass
class Survey_screen(Screen):
pass
class Finish_screen(Screen):
pass
class ImageButton(ButtonBehavior, Image):
pass
class Nq_button(Button):
pass
class MyPopup(Popup):
def show_popup(self, title_text, label_text, button_text):
mytext= label_text
content = BoxLayout(orientation="vertical")
content.add_widget(Label(text=mytext, font_size=20, text_size=(300, None)))
mybutton = Button(text="Ok!", size_hint=(1,.20), font_size=20)
content.add_widget(mybutton)
mypopup = Popup(content = content,
title = title_text,
auto_dismiss = False,
size_hint = (.5, .5))
mybutton.bind(on_press=mypopup.dismiss)
mypopup.open()
class nextqualApp(App):
icon = 'nextqual.png'
title = 'Pay / survey / join'
if __name__ == '__main__':
nextqualApp().run()
my .kv file is nextqual.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
Sm:
id: sm
transition: FadeTransition()
Pay_screen:
id: pay_screen
manager: sm
Survey_screen:
id: survey_screen
manager: sm
<Nq_check_label#Label>:
markup: True
multiline: True
<Nq_check_items#Label>:
color: 0,0,0,1
<Nq_rv>:
viewclass: 'Nq_check_items'
RecycleGridLayout:
cols: 3
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
<Pay_screen>:
name: 'pay'
total_pay: t_pay
BoxLayout:
orientation: "vertical"
padding: 6
font_size: '24'
BoxLayout:
size_hint_y: None
height: "40dp"
Button:
text: "Pay your bill"
on_release: app.root.current = 'pay'
Button:
text: "Tell us how we did"
on_release: app.root.current = 'survey'
Button:
text: "I'm finished"
BoxLayout:
BoxLayout:
padding: 12
orientation: 'vertical'
BoxLayout:
height: "40dp"
size_hint_y: None
Label:
text: 'Table: 4'
Label:
text: 'Server: Julie'
Label:
text: 'Check # 58645'
BoxLayout:
canvas:
Color:
rgb: 255,255,255,255
Rectangle:
size: self.size
pos: self.pos
Nq_rv:
BoxLayout:
height: "30dp"
size_hint_y: None
Label:
text: 'Total check:'
size_hint_x: 75
#This is the field I want to update!
Label:
id: t_pay
text: '0.00'
halign: 'right'
size_hint_x: 25
<Survey_screen>:
name: "survey"
BoxLayout:
orientation: "vertical"
padding: 6
font_size: '24'
BoxLayout:
size_hint_y: None
height: "40dp"
Button:
text: "Pay your bill"
on_release: app.root.current = 'pay'
Button:
text: "Tell us how we did"
on_release: app.root.current = 'survey'
Button:
text: "I'm finished"
BoxLayout:
BoxLayout:
height: "100dp"
size_hint_y: None
Label:
size_hint_x: 40
Button:
size_hint_x: 20
text:"Send survey"
halign: "center"
on_press: app.root.send_survey()
Label:
size_hint_x: 40
embryo asked for some sample data. the file 'bill.csv' looks like this:
1,Seafood Sampler,15.99
1,Tea Smoked Duck,19.95
2,Shredded Duck with Ginger,22
1,Deli Rueben,9.95
1,Sam Adams,3
1,Cotswold Premium,4
1,Btl Pinot Noir,25
The idea of creating custom classes is to give you custom properties, for example Nq_rv is not only a RecycleView but a class that you can new properties, for example you can give the property total_bill that has the information of the total. That property will be accessible from the outside so you can make a binding with the text of t_pay:
*.py
class Nq_rv(RecycleView):
total_bill = NumericProperty(0.00) # <-- new property
def __init__(self, **kwargs):
super(Nq_rv, self).__init__(**kwargs)
self.load_data()
def load_data(self):
bill_text = []
total = 0.0
with open('bill.csv') as bill:
bill_reader = csv.reader(bill)
for row in bill_reader:
for item, val in enumerate(row):
if item < 2:
item_text = val
else:
item_text = '{0:.2f}'.format(float(val))
total += float(val) #total accumulation
text_row = {'text': item_text}
bill_text.append(text_row)
self.data = bill_text
self.total_bill = total # <-- update property
*.kv
BoxLayout:
canvas:
Color:
rgb: 255,255,255,255
Rectangle:
size: self.size
pos: self.pos
Nq_rv:
id: rv # <-- set id
BoxLayout:
height: "30dp"
size_hint_y: None
Label:
text: 'Total check:'
size_hint_x: 75
#This is the field I want to update!
Label:
id: t_pay
text: '{0:.2f}'.format(rv.total_bill) # <--- binding
halign: 'right'
size_hint_x: 25

Python/Kivy : Remove space using python

I am using python-2.7 and kivy. I am trying to hide TextInput with blank space.
At this time i am using opacity property for hiding Textinput
self.row.abc.opacity = 0
Using this code TextInput is hiding but blank space not removed. Can someone tell me how to remove blank space or another better solution for hiding Textinput with blank space.
test.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
Window.size = (450, 425)
class display(Screen):
def __init__(self, **kwargs):
super(display, self).__init__(**kwargs)
def add_more(self):
self.ids.rows.add_row()
class Row(BoxLayout):
button_text = StringProperty("")
id = ObjectProperty(None)
col_data = ListProperty(["", ""])
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.row = Row(button_text=str(self.row_count))
self.row.abc.opacity = 0
self.row.col_data[1] = 'Test1'
self.add_widget(self.row)
class test(App):
def build(self):
return self.root
if __name__ == '__main__':
test().run()
test.kv
<Row>:
abc: abc
#state1 : state1
orientation: "horizontal"
spacing: 0, 5
Button:
text: root.button_text
size_hint_x: .2
TextInput:
id : abc
size_hint_x: .8
text : root.col_data[0]
TextInput:
size_hint_x: .8
text : root.col_data[1]
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: "Value1"
valign: 'bottom'
Label:
size_hint_x: .8
text: "Value2"
valign: 'bottom'
Rows:
id: rows

Python : How to remove widget in kivy

I have two file demo.py and demo.kv.
when i run demo.py after click on menu then shows +Add more button.When i click on +Add more button then three row add dynamic because i am using loop there.Every time add three row dynamic
But can anyone tell me when i add new row then how to remove previous three row?
Every time should be show only 3 new row and previous row should be delete.I am using code
def add_more(self):
self.remove_widget(Row())
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
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 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)
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_more()
def add_more(self):
self.remove_widget(Row())
for x in range(0, 3):
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'
<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"
<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
remove_widget must receive as argument the instance of the child widget to be removed. Since you can get widget's children using its children attribute, to remove the previous three rows you can do the following:
def add_more(self):
if self.children:
for child in self.children[:3]:
self.remove_widget(child)
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
However, it's simpler to use clear_widgets method:
def add_more(self):
self.clear_widgets(self.children[:3])
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
Since you actually delete all the rows in the BoxLayout, you can do:
def add_more(self):
self.clear_widgets()
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
Edit:
To reset the index simply disregard self.row_count and use the value returned by range:
def add_more(self):
self.clear_widgets()
for x in range(1, 4):
self.add_widget(Row(button_text=str(x)))

python/kivy : access attribute value in .kv file

When I click on Account(root.display_account()) then call display_account().After that RVACCOUNT() function call .After that when i click on +Add Account then def add_account(self): call
I have a class AccountPopup which define a attribute state_text and assign value text:'Testing' in .kv file
How to get value of state_text 'Testing' and pass in on_text: root.filter(self.text,state_text) and print in def filter function.
test.py
class AccountPopup(Popup):
state_text = ObjectProperty(None)
popupAccountCity = ObjectProperty(None)
def display_cities_treeview_account(self, instance):
if len(instance.text) > 0:
#if self.popupAccountCity is None:
self.popupAccountCity = TreeviewCityAccount(self.state_text.text)
self.popupAccountCity.filter(instance.text,self.state_text.text)
self.popupAccountCity.open()
class TreeviewCityAccount(Popup):
state_text = ObjectProperty(None)
def __init__(self,state_text, **kwargs):
print(state_text)
def filter(self, f,state):
print(state)
class RVACCOUNT(BoxLayout):
def add_account(self):
self.mode = "Add"
popup = AccountPopup(self)
popup.open()
class MainMenu(BoxLayout):
def display_account(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvaccount = RVACCOUNT()
self.content_area.add_widget(self.rvaccount)
class FactApp(App):
title = "Test"
def build(self):
self.root = Builder.load_file('test.kv')
return MainMenu()
if __name__ == '__main__':
FactApp().run()
test.kv
<AccountPopup>:
state_text:state_text
TextInput:
id:state_text
text:'Testing'
<TreeviewCityAccount>:
BoxLayout
orientation: "vertical"
TextInput:
id: treeview
size_hint_y: .1
on_text: root.filter(self.text,state_text)
<RVACCOUNT>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: .07, .03
text: "+Add Account"
on_press: root.add_account()
<MainMenu>:
content_area: content_area
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
MenuButton:
id: btn
text: 'Master'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
DropdownButton:
text: 'Account'
size_hint_y: None
height: '32dp'
on_release: root.display_account()
Can someone help me?
You should reference it as self.state_text everywhere, also make it a StringProperty in the py file and can than access it as
on_text: root.filter(self.text,root.state_text)
root in kv refers to the most left widget aka <TreeviewCityAccount>: in your case.
See https://kivy.org/docs/api-kivy.lang.html
Alternatively you can work with ids in the kv file.
the value you are looking for is not in your immediate root which is why this is not working.The say thing to do is get the full path to that property like so:
Snippet:
<AccountPopup>:
id: ac_popup
#bunch of code
<TreeviewCityAccount>:
#chunk of code
TextInput:
id: tree view
on_text:root.filter(self.text,app.ac_popup.state_text
Also,generally,it's a good idea to id your classes mate
Disclaimer:code not tested

Categories

Resources