Kivy是面向触屏设备的,对键盘,遥控器等输入设备的处理比较弱,但是有时候我们又需要实现对按键的处理,如通过方向键切换焦点,这篇文章来讨论下如何去实现。
在看下面的代码之前,最好是对Kivy的UI系统有一个基本的了解。
按照惯例,我们先上代码,然后再对代码进行解释:
focustest.py
import kivy kivy.require('1.8.0') from kivy.app import App from kivy.properties import StringProperty,BooleanProperty from kivy.core.window import Window from kivy.uix.widget import Widget from kivy.uix.button import Button from kivy.graphics import Color, Ellipse, Line,Rectangle from kivy.uix.boxlayout import BoxLayout class MyButton(Button): focus = BooleanProperty(False) def __init__(self,**kwargs): super(MyButton,self).__init__(**kwargs) # with self.canvas.before: rect=(self.pos[0]+4,self.pos[1]+4,self.size[0]-8,self.size[1]-8) with self.canvas.after: self.edge_color = Color(0,0,0,0) self.edge = Line(rectangle=rect,width=4,joint='round') self.edge_center_color = Color(1,1,1,0) self.edge_center = Line(rectangle=rect,width=1) # listen to size and position changes self.bind(pos=self.update_rect,size=self.update_rect) self.focus=False def update_rect(self,instance,value): rect=(self.pos[0]+4,self.pos[1]+4,self.size[0]-8,self.size[1]-8) self.edge.rectangle=rect self.edge_center.rectangle=rect def set_focus(self): self.focus = True self.parent.on_focus_changed(self) def on_focus(self,instance,focused): print '++++++++++++++on_focus:',focused if focused: self.edge_color.rgba = (0.4,0.4,1,1) self.edge_center_color.rgba=(1,1,1,1) else: self.edge_color.rgba = (0,0,0,0) self.edge_center_color.rgba=(0,0,0,0) def on_press(self): pass def on_release(self): pass def on_touch_down(self,touch): print '++++++++++++++++++on_touch_down:',touch if self.collide_point(*touch.pos): self.set_focus() super(MyButton,self).on_touch_down(touch) class FocusTest(BoxLayout): def __init__(self,**kargs): super(FocusTest,self).__init__(**kargs) self.buttons = [] btn1 = MyButton(text='1',on_press=self.on_press) btn1.size_hint=(0.5,0.5) self.add_widget(btn1) Window.bind(on_key_down=self.on_key_down) btn = MyButton(text='2',on_press=self.on_press) btn.size_hint=(0.2,0.2) btn.pos_hint={'top':0.8} self.add_widget(btn) btn = MyButton(text='3',on_press=self.on_press) btn.size_hint=(0.2,0.3) self.add_widget(btn) self.children[-1].set_focus() self.index = len(self.children) - 1 with self.canvas.before: Color(0, 1, 0, 1) self.rect = Rectangle(size=self.size,pos=self.pos) Color(1, 1, 0, 1) self.border = Line(rectangle=self.pos+self.size,width=3) # listen to size and position changes self.bind(pos=FocusTest.update_rect, size=FocusTest.update_rect) for item in self.children: print item.text def on_focus_changed(self,focusitem): index = 0 for item in self.children: if focusitem is item: self.index = index else: item.focus = False index += 1 def on_key_down(self,window,key,scancode,a,b): print 'on_key_down:',key,scancode if key == 275: #left if self.index == 0: self.index = len(self.children) - 1 else: self.index -= 1 elif key == 276: #right if self.index == len(self.children) - 1: self.index = 0 else: self.index += 1 self.children[self.index].set_focus() def on_key_up(self,window,key,scancode): pass def on_press(self,control): print control def on_release(self,control): print control def update_rect(self,value): self.rect.pos = self.pos self.rect.size = self.size self.border.rectangle=self.pos+self.size class MyApp(App): def build(self): return FocusTest() def on_pause(self): return True if __name__ == '__main__': MyApp().run()
接下来看下这130行的代码做了什么:
先挑重点的来讲:
在FocusTest.__init__中,有一行很关键的代码:
Window.bind(on_key_down=self.on_key_down)
这行代码就是用于在Window注册一个key down的消息监听,以便接收按键消息。
接下来看下on_key_down做了些什么事:
def on_key_down(self,window,key,scancode,a,b): print 'on_key_down:',key,scancode if key == 275: #left if self.index == 0: self.index = len(self.children) - 1 else: self.index -= 1 elif key == 276: #right if self.index == len(self.children) - 1: self.index = 0 else: self.index += 1 self.children[self.index].set_focus()
self.children[self.index].set_focus()
我们来看看MyButton.set_focus做了什么事:
def set_focus(self):
self.focus = True
self.parent.on_focus_changed(self)
self.focus是一个BooleanProperty,给它赋值将会触发:on_focus,有疑问可以看下下面的文章:
Kivy A to Z -- Kivy之Properties
on_focus方法就是根据MyButton是否获取到焦点来进行画不同的矩形框:
def on_focus(self,instance,focused):
print '++++++++++++++on_focus:',focused
if focused:
self.edge_color.rgba = (0.4,0.4,1,1)
self.edge_center_color.rgba=(1,1,1,1)
else:
self.edge_color.rgba = (0,0,0,0)
self.edge_center_color.rgba=(0,0,0,0)
最后看下self.parent.on_focus_changed(self)做了什么,parent即为FocusTest:
def on_focus_changed(self,focusitem):
index = 0
for item in self.children:
if focusitem is item:
self.index = index
else:
item.focus = False
index += 1
这里的代码就是将其它Button设置为非焦点状态。
最后再来看下MyButton.__init__里的:
self.bind(pos=self.update_rect,size=self.update_rect)
这行代码的作用就是监听Button大小和位置的改变,并调整画焦点时矩形框的大小。
OK,that's ALL