When calling function by touchdown event, kivy is iterating all the Text Input widgets of the layout.
I have this code here:
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
sm = ScreenManager()
class MenuScreen(Screen):
def __init__(self, screen_name):
super(MenuScreen, self).__init__()
self.name = screen_name
self.selected_entry = self.last_selected_entry = None
self.layout = FloatLayout(size_hint_x=None, size_hint_y=None, size=Window.size)
self.add_widget(self.layout)
for col in range(4):
entry = TextInput(text=f'Entry {col + 1}', size_hint=(None, None), size=(0.22 * Window.width, 0.105 * Window.height), font_size=25, halign='center', unfocus_on_touch=False, keyboard_mode='managed')
entry.pos_hint_x = entry.pos_hint_y = None
entry.center_x = 0.14 * Window.width + col * 0.24 * Window.width
entry.center_y = 0.5 * self.layout.height
entry.bind(on_touch_down=self.identify_selected_entry)
if col == 0:
self.selected_entry, self.last_selected_entry, entry.focus = entry, entry, True
self.layout.add_widget(entry)
def identify_selected_entry(self, instance, event=None):
print(f'Text of clicked entry: {instance.text}')
if self.last_selected_entry:
self.last_selected_entry.focus = False
self.selected_entry = self.last_selected_entry = instance
class MainScreen(App):
global sm
def build(self):
sm.add_widget(MenuScreen('Menu'))
return sm
if __name__ == '__main__':
MainScreen().run()
This is what happens when I click on the fist entry or in a random place of the layout:
Text of clicked entry: Entry 4
Text of clicked entry: Entry 3
Text of clicked entry: Entry 2
Text of clicked entry: Entry 1
And this happens when I click on the last entry:
Text of clicked entry: Entry 4
So kivy is not calling the function only for the entry selected, but instead is iterating all the entries of the layout, from last to fist. I don't know if this is the normal behavior of kivy, but I would like to call the function only for the entry I selected.
The on_touch_down
events (as well as others) are distributed to all the widgets. So any widget that wants to determine if the event
was touched on itself, must test the position of the touch to determine if the touch was within itself. You can do that in your code by adding a call to collide_point()
to your identify_selected_entry()
:
def identify_selected_entry(self, instance, event=None):
if event and instance.collide_point(*event.pos):
print(f'Text of clicked entry: {instance.text}')
else:
return False
if self.last_selected_entry:
self.last_selected_entry.focus = False
self.selected_entry = self.last_selected_entry = instance
return True