kivy/examples/widgets/focus_behavior.py

99 lines
3.5 KiB
Python

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.behaviors import FocusBehavior
from kivy.graphics import Color, Rectangle
class FocusWithColor(FocusBehavior):
''' Class that when focused, changes its background color to red.
'''
_color = None
_rect = None
def __init__(self, **kwargs):
super(FocusWithColor, self).__init__(**kwargs)
with self.canvas:
self._color = Color(1, 1, 1, .2)
self._rect = Rectangle(size=self.size, pos=self.pos)
self.bind(size=self._update_rect, pos=self._update_rect)
def _update_rect(self, instance, value):
self._rect.pos = instance.pos
self._rect.size = instance.size
def on_focused(self, instance, value, *largs):
self._color.rgba = [1, 0, 0, .2] if value else [1, 1, 1, .2]
class FocusLabel(FocusWithColor, Label):
'''A label, which in addition to turn red when focused, it also sets the
keyboard input to the text of the label.
'''
def keyboard_on_key_down(self, window, keycode, text, modifiers):
'''We call super before doing anything else to enable tab cycling
by FocusBehavior. If we wanted to use tab for ourselves, we could just
not call it, or call it if we didn't need tab.
'''
if super(FocusLabel, self).keyboard_on_key_down(window, keycode,
text, modifiers):
return True
self.text = keycode[1]
return True
class FocusGridLayout(FocusWithColor, GridLayout):
pass
class FocusBoxLayout(FocusWithColor, BoxLayout):
pass
class FocusApp(App):
def build(self):
root = FocusBoxLayout(padding=[10, 10], spacing=10)
self.grid1 = grid1 = FocusGridLayout(cols=4, padding=[10, 10],
spacing=10)
self.grid2 = grid2 = FocusGridLayout(cols=4, padding=[10, 10],
spacing=10)
root.add_widget(FocusLabel(text='Left', size_hint_x=0.4))
root.add_widget(grid1)
root.add_widget(grid2)
root.add_widget(FocusLabel(text='Right', size_hint_x=0.4))
for i in range(40):
grid1.add_widget(FocusLabel(text='l' + str(i)))
for i in range(40):
grid2.add_widget(FocusLabel(text='r' + str(i)))
# make elements 29, 9 un-focusable. The widgets are displayed in
# reverse order, so 9 = 39 - 10
grid2.children[30].text = grid1.children[14].text =\
grid2.children[15].text = grid1.children[34].text = 'Skip me'
grid2.children[15].is_focusable = False
grid2.children[30].is_focusable = False
# similarly, make 39 - 14 = 25, and 5 un-focusable
grid1.children[14].is_focusable = False
grid1.children[34].is_focusable = False
# don't move focus passed this element
grid2.children[35].focus_next = StopIteration
grid2.children[35].text = 'Stop forward'
# exchange the links between the sides so that it'll skip to the other
# side in the middle. Remember that children are displayed reversed
# in layouts.
grid1.children[10].focus_next = grid2.children[9]
grid2.children[10].focus_next = grid1.children[9]
grid1.children[10].text = '-->'
grid2.children[10].text = '<--'
return root
if __name__ == '__main__':
FocusApp().run()