I am trying to add a set of buttons to a grid layout scroll view using for loop. But the on press event is being triggered for all the buttons even before pressing the buttons. How can I fix this?
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.app import runTouchApp
import webbrowser
def btnsclicked(id, url):
print 'btn id '+id+' clicked'
webbrowser.open(url)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(5):
url= 'https://www.google.com'
btn = Button(text=str(i), size_hint_y=None, height=40, id='b'+str(i))
btn.bind(on_press =btnsclicked('b'+str(i), url))
layout.add_widget(btn)
root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root.add_widget(layout)
runTouchApp(root)
because you are actually calling your callback when passing args:
btn.bind(on_press =btnsclicked('b'+str(i), url))
Doc example says:
def callback(instance):
print('The button <%s> is being pressed' % instance.text)
btn1 = Button(text='Hello world 1')
btn1.bind(on_press=callback)
You have to pass a function (not a function call) accepting only 1 argument: instance of the activated widget.
do this using lambda
expressions that define functions in-line:
btn.bind(on_press = lambda x : btnsclicked('b'+str(i), url))
When an event is triggered, the on_press
callback is called with one argument: the widget id. That calls your lambda
function which calls btnsclicked
discarding this argument (that you don't need here), but passing your text id and the url you want to associate to.