Why do my kivy buttons act pressed the moment they are created in python?
So, let me start by saying I know that there seems to be a answer to this question here:
on_press in Kivy keeps running at start up instead
...however, there is no working example. I have tried to copy the example there to understand the answer, but lack the experience to do fill in what's missing from the example.
So, this will probably be an easy answer for someone who looks at the other answer, can apply it here, and explain in plainer english for the noob.
Here is a small working example of the problem:
import kivy
kivy.require('1.7.2') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
i = ['some', 'words']
class HomeScreen(Screen):
grid_l = ObjectProperty(None)
top_lbl = ObjectProperty(None)
def search_btn_pressed(self):
grid = self.grid_l
grid.bind(minimum_height=grid.setter('height'),
minimum_width=grid.setter('width'))
for result in i:
btn1 = Button(size_hint=(1, None))
btn1.text = '%r' % result
btn1.bind(on_release=self.btn1_pressed(result))
btn2 = Button(size_hint=(1, None))
btn2.text = 'Remove result buttons'
btn2.bind(on_release=self.btn2_pressed)
grid.add_widget(btn1)
grid.add_widget(btn2)
def btn1_pressed(self, result, *args):
new_text = result
self.top_lbl.text = new_text
def btn2_pressed(self, *args):
self.grid_l.clear_widgets()
#pass
class buttons_pressedApp(App):
def build(self):
return HomeScreen()
if __name__ == '__main__':
buttons_pressedApp().run()
And the kv file:
#:kivy 1.7.2
<HomeScreen>:
scroll_view: scrollviewID
top_lbl: lblID
grid_l: gridlayoutID
AnchorLayout:
size_hint: 1, .1
pos_hint: {'x': 0, 'y': .9}
anchor_x: 'center'
anchor_y: 'center'
Label:
id: lblID
text: 'Button Tester'
Button:
size_hint: 1, .1
pos_hint: {'x': 0, 'y': .8}
text: 'Add theoretical search results'
on_release: root.search_btn_pressed()
ScrollView:
id: scrollviewID
orientation: 'vertical'
pos_hint: {'x': 0, 'y': 0}
size_hint: 1, .8
bar_width: '8dp'
GridLayout:
id: gridlayoutID
cols: 1
size_hint: 1, None
row_default_height: 40
row_force_default: False
As you can see when you run it, the first button created in kivy works super. However, you will also notice that the top label changed immediately, indicating that the first dynamically created button already executed the on_release function.
You can't tell that the second dynamically created button, "Remove result buttons" was already executed because it removed all buttons when there were still none. However, it is evident the "Remove result buttons" button is being immediately executed when you press the "Add theoretical search results" button a second time. It should add two more buttons, but seems like nothing happens. This is because the "Remove result buttons" button is removing the previous two buttons, and then they are immediately being replaced.
Then, of course, neither of the buttons seem to do anything.
Should be easy for someone to fix the example given the similar question!
Thanks in advance.
EDIT:
I've altered btn2 to reflect inclement's answer. Works perfectly. However, as he pointed out, when I do the same to btn1, some default arguments are being passed into the method and it gives an error. So, I left btn1 as before with the parenthesis and 'result' inside them as the argument. Of course, this is run immediately and return nothing to be bound (as inclement explained). I want to be able to pass in 'result' as already defined in the example, but naturally not run it immediately. My apologies.. I should have written it this way the first time.
EDIT 2, the answer:
To reflect inclements last comment, I just wanted to posted the whole working example again with the answer included.
import kivy
kivy.require('1.7.2') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from functools import partial
i = ['some', 'words']
class HomeScreen(Screen):
grid_l = ObjectProperty(None)
top_lbl = ObjectProperty(None)
def search_btn_pressed(self):
grid = self.grid_l
grid.bind(minimum_height=grid.setter('height'),
minimum_width=grid.setter('width'))
for result in i:
btn1 = Button(size_hint=(1, None))
btn1.text = '%r' % result
btn1.bind(on_release=partial(self.btn1_pressed, result))
btn2 = Button(size_hint=(1, None))
btn2.text = 'Remove result buttons'
btn2.bind(on_release=self.btn2_pressed)
grid.add_widget(btn1)
grid.add_widget(btn2)
def btn1_pressed(self, result, *args):
new_text = result
self.top_lbl.text = new_text
def btn2_pressed(self, *args):
self.grid_l.clear_widgets()
#pass
class buttons_pressedApp(App):
def build(self):
return HomeScreen()
if __name__ == '__main__':
buttons_pressedApp().run()
It works!