id

.kv 내에서만 접근 가능한 아이디다.
보통 맨 앞에 _를 붙이지만, 구분하기 위한 권고사항이지 필수는 아니다

attribute

어떤 widget에 attribute를 생성하고, id를 여기 넣어주면 그 attribute로 접근할 수 있다.

<ComicCreator>:
    AnchorLayout: ...
        ToolBox:
            id: _tool_box
            drawing_space: _drawing_space
    AnchorLayout: ...
        DrawingSpace:
            id: _drawing_space

commiccreator.kv의 ToolBox에서 drawing_space attribute는 _drawing_space(id)를 가지고 있으며, python에서 drawing_space로 여기에 접근 가능하다.
root도 동일한 방식이다.

etc.

root: base widget in the rule hierarchy
self: current widget
app: the instance of the application

Touch event

touch event는 mouse, finger touch, magic pen touch으로 나뉘며, 아래 event는 mouse, finger touch에서 사용 가능하다.

  • on_touch_down: new touch start
  • on_touch_move: the touch is moved
  • on_touch_up: the touch ends

각 touch event는 parameter(touch)로 여러 정보를 갖는 MotionEvent를 받는다.

    def on_touch_down(self, touch):
        if self.collide_point(touch.x, touch.y):
            self.select()
            return True
        return super(DraggableWidget, self).on_touch_down(touch)

event가 진행되면 True를 return하고, event가 widget 밖으로 나가면, children에 전달해 return을 받는다.
유사하게 super.on_touch_~ 으로 chidren의 event를 신경쓸 수 있다.

collide_point

모든 widget이 app(coordinate space)에서 발생하는 touch event(MotionEvent)를 받지만, 그 event가 특정 widget에서 발생하는지 확인하는 보편적인 방법이다.

dynamic create/deleate canvas

with self.canvas:
                self.selected = Line(rectangle=(0, 0, self.width, self.height),
                dash_offset=2)

with self.canvas를 통해 canvas에 instructions를 넣을 수 있다.
Line instance를 self.selected에 넣어서 언제든 삭제할 수 있도록 구현할 수 있다.

if self.selected:
    self.canvas.remove(self.selected)
    self.selected = None

self.canvas.remove(self.selected)를 통해 canvas에 self.selected를 지울 수 있다.

localizing coordinates

to_parent() 같이, 현재 widget에서 구현하지만, 움직일 공간이 parent, 혹은 parent’s parent와 같은 경우 coordinates의 범위를 지정해주는 것.
RelativeLayout은 coordinate의 위치 값들이 다 다르기 때문에 이런 방법이 필요하다.

  • RelativeLayout이 아닌 layout들은 그 상위에 대해 절대적인 coordinate 값을 가지고 있음

  • to_parent(): transform relative coordinates inside RelativeLayout to the parent of RelativeLayout. 부모의 coordinate에 접근할 수 있다.
  • to_local(): transform the coordinates of parent of RelativeLayout to RelativeLayout
  • to_window(): transform the coordinates of the current widget to absolute coordinate with respect to the window
  • to_widget(): transform the absolute coordinates to coordinates within the parent of the current widget

.py와 .kv 연결

layout.add_widget(w)으로 layout에 widget을 더해준다.
#:import toolbox toolbox으로 toolbox를 .kv에 import 한다. (.kv에서도 python code를 import할 수 있다.)

comiccreator.py comiccreator.kv (얘가 toolbox를 사용) - toolbox.py - toolbox.kv

위와 같이, commiccreator가 main이 되고 toolbox를 사용하는 상황에서

  1. comiccreator.py에서 comiccreator.kv를 사용하고 (kv에서 자동으로)
  2. commiccreator는 toolbox.kv를 내부적으로 사용하고 (.py에서 Builder.load_file로 load)
  3. toolbox.kv는 toolbox.py의 구현을 사용한다 (.kv에서 #:import toolbox toolbox로 import)

즉, toolbox.py가 main이었다면 import를 안해도 .kv를 가져갔겠지만, toolbox가 main이 아니라 사용되는 상황에서, .py를 import 해줘야 했음.

bind/unbind

binding에는 2가지 방법이 존재한다.

1. at .py, it works for every instance about this class

python에서는 bind하면 전체 적용되는 것을 피하기 위해 touch_down의 경우 overriding하여 사용하고, 나머지에 대해 bind 하는 방식을 사용한다.
(we didn’t want the on_touch_move, on_touch_up events active all the time.)
move와 up은 touch_down이 발생한 이후에 발생할 수 있으므로, 이 이벤트들을 항상 active 상태에 두는 것이 아니라, touch_down시에 bind를 통해 관리하도록 하는 것이다.

def on_touch_down(self, touch):
    ...
    self.draw(ds, x, y)

def draw(self, ds, x, y):
    ...
    ds.bind(on_touch_move=self.update_figure)
    ds.bind(on_touch_up=self.end_figure)

def update_figure(self, ds, touch):
def end_figure(self, ds, touch):

2. at .kv, it works only for this instance

특정 instance에 대해 bind하기 때문에 collide_point를 사용할 필요가 없다.

  • Button: on_press:on_release:
<GeneralOptions>:
    Button:
        text: 'Clear'
        on_press: root.clear(*args) # clear, remove는 .py의 GeneralOptions에 구현된 함수
    Button:
        text: 'Remove'
        on_release: root.remove(*args)
  • ToggleButton: on_state - .py에서 ‘down’, ‘normal’로 구분

etc

  • clear_widgets(): 모든 widget을 지움
  • remove_widget(x.children[0]): 가장 최근에 추가된 widget을 지움

Kivy property

property가 정의되면 Kivy는 내부적으로 property와 연관된 event를 생성하고, 이 event는 ‘on_property_name’ method와 연결된다.

translation = ListProperty(None)
    def on_translation(self, instance, value):

따라서, property에 값을 넣어주면 on_property 가 자동으로 실행 된다.

  • 이는 kivy에서 굉장히 중요한 개념으로, 내부적으로 많이 사용됨.
  • 다른 클래스에서 특정 property를 바꿈으로써 on_property를 trigger할 수 있음.

center_x도 property를 내부적으로 사용하는 것이다.
.kv의 vertex instruction의 attribute도 내부적으로 property로 사용 된다.
python property와 혼동해서는 안된다.
Kivy Property는 항상 attribute 지만, attribute가 모두 Kivy Property는 아니다.

  • attribute: used to describe variables(references, objects, instances) that belongs to class
class StatusBar(BoxLayout):
    counter = NumericProperty(0)
    previous_counter = 0

kivy property는 static attribute로 선언되나, internally transformed to attribute instansces.

  • counter는 static하게 선언되나 attribute instances가 되고, previous_counter는 static attribute로 되어 all StatusBar가 share..
    • class name(StatusBar.previous_counter)이나 __class__(__class_.previous_counter)로 바로 접근 가능
  • __init__ 안에서 선언되는 것들은 instance 임. 즉 not shared..

Kivy property

BoundedNumericProperty: set the maximum and minimum values
AliasProperty: extend the properties, create our own properties
NumericProperty
StringProperty
ListProperty
DictProperty
ObjectProperty
StringProperty