Reputation: 423
So I am making a calculator/unit conversion app, and want a label to display the calculation dynamically as the text input value changes. For instance, lets say that the calculation part of this is a simply multiply by 3. So, The user inputs, say, 5 into the text input. Then, they click the Calculate button, which will multiply it by 3. Then, I want a label to display this calculation. Currently, I can't figure out how to get that to happen! Heres my code:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
FLOAT_LAYOUT = FloatLayout(size=(300, 300))
title_label = Label(text='0',
font_size=20,
pos_hint={'x': .4, 'y': .8},
size_hint=(.2, .2))
text_box = TextInput(multiline=False,
font_size=20,
pos_hint={'x': .4, 'y': .3},
size_hint=(.2, .2))
calculate_button = Button(text='Calculate',
font_size=20,
pos_hint={'x': .4, 'y': .1},
size_hint=(.2, .1))
class calculator_app(App):
def build(self):
FLOAT_LAYOUT.add_widget(title_label)
FLOAT_LAYOUT.add_widget(text_box)
FLOAT_LAYOUT.add_widget(calculate_button)
return FLOAT_LAYOUT
def calculate(self):
title_label.text = str(float(text_box.text)*3)
calculator_object = calculator_app()
calculator_object.run()
calculate_button.bind(on_press=calculator_object.calculate())
Clearly I am doing something wrong. Is .bind(on_press=...)
not the right way to go about this? Thanks in advance!
EDIT: Here is the error message:
AssertionError: None is not callable
This pertains the the line: calculate_button.bind(on_press=calculator_object.calculate())
Upvotes: 0
Views: 2151
Reputation: 16031
run()
method or return FLOAT_LAYOUT
calculate()
methodIn general, property callbacks are called with 2 arguments (the object and the property’s new value) and event callbacks with one argument (the object).
class calculator_app(App):
def build(self):
FLOAT_LAYOUT.add_widget(title_label)
FLOAT_LAYOUT.add_widget(text_box)
FLOAT_LAYOUT.add_widget(calculate_button)
return FLOAT_LAYOUT
def calculate(self, instance):
if len(text_box.text) > 0:
title_label.text = str(float(text_box.text)*3)
calculator_object = calculator_app()
calculate_button.bind(on_press=calculator_object.calculate)
calculator_object.run()
class calculator_app(App):
def build(self):
FLOAT_LAYOUT.add_widget(title_label)
FLOAT_LAYOUT.add_widget(text_box)
FLOAT_LAYOUT.add_widget(calculate_button)
calculate_button.bind(on_press=self.calculate)
return FLOAT_LAYOUT
def calculate(self, instance):
if len(text_box.text) > 0:
title_label.text = str(float(text_box.text)*3)
calculator_object = calculator_app()
calculator_object.run()
Upvotes: 1
Reputation: 243955
You have the following errors:
What is placed after run() will only run when the window is closed, and the goal of the GUI is to run everything while the GUI is open.
On the other hand, the bind method requires that you give the name of the callback, not the callback evaluated as you are doing.
bind passes parameters that must be received by the callback, such as the instance that generates the call, in this case the button, so you should place those values as arguments.
The TextInput can receive values that are not numbers, for example in the case that the TextInput is empty, that could cause problems so a possible solution is to use the exceptions.
Solution:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
FLOAT_LAYOUT = FloatLayout(size=(300, 300))
title_label = Label(text='0',
font_size=20,
pos_hint={'x': .4, 'y': .8},
size_hint=(.2, .2))
text_box = TextInput(multiline=False,
font_size=20,
pos_hint={'x': .4, 'y': .3},
size_hint=(.2, .2)
)
calculate_button = Button(text='Calculate',
font_size=20,
pos_hint={'x': .4, 'y': .1},
size_hint=(.2, .1))
class calculator_app(App):
def build(self):
FLOAT_LAYOUT.add_widget(title_label)
FLOAT_LAYOUT.add_widget(text_box)
FLOAT_LAYOUT.add_widget(calculate_button)
return FLOAT_LAYOUT
def calculate(self, *args):
print(args)
try:
title_label.text = str(float(text_box.text)*3)
except ValueError:
print("Not a float")
calculator_object = calculator_app()
calculate_button.bind(on_press=calculator_object.calculate)
calculator_object.run()
Upvotes: 1