Changing the text of a button (from a child class) when a function is triggered in another child class. Kivy

143 views Asked by At

Here I have program that calculates profit based on expenses and revenue.

enter image description here

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)   ``````
1

There are 1 answers

4
ApuCoder On

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()