วันจันทร์ที่ 28 กันยายน พ.ศ. 2558

Kivy(bind and unbinding event)

ในบทนี้เราจะมาเริ่มจากการคลิกเมาส์เพื่อวาดรูปใน DrawingSpace แล้วลากเมาส์แล้วกำหนดขนาดของวงกลมได้เราถึงมาทำเริ่มสร้างส่วนประกอบ Draggablewidget ซึ่งจะทำให้เราสามารถลากมันบน DrawingSpace ได้ โดย Diagram จะช่วยเราในการเข้าใจสืบทอดโครงสร้างจาก toolbox.py




จาก Diagram จะเห็นว่าได้นำ ToolButton กับ ToolStickman จากที่อธิบายในตัวอย่างที่แล้วมาใช้แล้วยังเพิ่มไปอีก 3 class คือ ToolFigure, Toolline, ToolCircle โดย class  ToolFigure นั้นจะมี 6 เมทอด โดยมีโค้ดดังนี้

โค้ดในไฟล์ toolbox.py (classToolFigure)

class ToolFigure(ToolButton):
    def draw(self, ds, x, y):
        (self.ix, self.iy) = (x, y)
        with ds.canvas:
            self.figure = self.create_figure(x, y, x+1, y+1)
        ds.bind(on_touch_move = self.update_figure)
        ds.bind(on_touch_up = self.end_figure)
"""ฟังก์ชั่นนี้จะทำการ override ฟังก์ชั่น draw ของ ToolButton ตำแหน่งที่เรากดลงไปนั่นจะบอกถึงจุดเริ่มต้นของรูปร่างของเราไม่งั้นก็จุดกึ่งกลางของวงกลมหรือจุดสิ้นสุดของเส้น"""
    def update_figure(self, ds, touch):
        if ds.colide_point(touch.x, touch.y):
            (x, y) = ds.to_widget(touch.x, touch.y)
            ds.canvas.remove(self.figure)
            with ds.canvas:
                self.figure = self.create_figure(self.ix, self.iy, x, y)
"""เมทอดนี้จะทำการเพิ่มจุดสิ้นสุดของรูปร่างเมื่อเวลาที่เราทำการลากอย่างไรก็ตามจุดสิ้นสุดของเส้นหรือเรเดียน(ระยะจากจุดเริ่มจนถึงจุดจบ)ของวงกลม"""
    def end_figure(self, ds, touch):
        ds.unbind(on_touch_move = self.update_figure)
        ds.unbind(on_touch_up = self.end_figure)
        ds.canvas.remove(self.figure)
        (fx, fy) = ds.to_widget(touch.x, touch.y)
        self.widgetize(ds, self.ix, self.iy, fx, fy)
"""เมทอดนี้จะบอกถึงจุดจบสุดท้ายของรูปร่างมีวิธีการเหมือนฟังก์ชั่น update_figure เราสามารถใส่ค่าสุดท้ายลงใน DraggableWidget ได้(ดูใน widgetize)"""
    def widgetize(self, ds, ix, iy, fx, fy):
        widget = self.create_widget(ix,iy,fx,fy)
        (ix,iy) = widget.to_local(ix,iy,relative=True)
        (fx,fy) = widget.to_local(fx,fy,relative=True)
        widget.canvas.add( self.create_figure(ix,iy,fx,fy))
        ds.add_widget(widget)
"""เมทอดนี้จะทำการสร้าง DraggableWidget และ วางรูปร่างที่เราสร้างลงไปและใช้ จุดร่วม 4 จุดในการกำหนดค่าให้ถูกต้องโดยการใช้ localization method"""
    def create_figure(self,ix,iy,fx,fy):
        pass
    def create_widget(self,ix,iy,fx,fy):
        pass

แล้วก็เราจะมาทำการเพิ่มเติม class TooLine และ ToolCircle โดยทำการสืบทอดคลาสแม่มาจาก ToolFigure โดยจะเป็นส่วนสุดท้ายใน ไฟล์ toolbox.py โดยมีโค้ดให้คือ

class ToolLine(ToolFigure):
    def create_figure(self, ix, iy, fx, fy):
        return Line(points=[ix, iy, fx, fy])
    def create_widget(self, ix, iy, fx, fy):
        pos = (min(ix, fx), min(iy, fy))
        size = (abs(fx-ix), abs(fy=iy))
        return DraggableWidget(pos = pos, size = size)
class ToolCircle(ToolFigure):
    def create_figure(self, ix, iy, fx, fy):
        return Line(circle = [ix, iy, math.hypot(ix-fx, iy-fy)])
    def create_widget(self, ix, iy, fx, fy):
        r = math.hypot(ix-fx, iy-fy)
        pos = (ix-r, iy-r)
        size = (2*r, 2*r)
        return DraggableWidget(pos = pos , size = size)

 ซึ่งสุดท้ายเราก็ต้องไปแก้ไฟล์ toolbox.kv โดยโค้ดที่เราต้องจัดการแก้คือ

#:import toolbox toolbox
<ToolButton>:
  size_hint: None,None
  size: 48,48
  group: 'tool'
  canvas:
    PushMatrix:
    Translate:
      xy: self.x,self.y
  canvas.after:
    PopMatrix:
<ToolBox@GridLayout>:
  cols: 2
  padding: 2
  tool_circle: _tool_circle
  tool_line: _tool_line
  tool_stickman: _tool_stickman
  ToolCircle:
    id: _tool_circle

    canvas:
      Line:
        circle: 24,24,14
  ToolLine:
    id: _tool_line

    canvas:
      Line:
        points: 10,10,38,38
  ToolStickman:
    id: _tool_stickman

    StickMan:
        pos_hint: {'center_x':.5,'center_y':.5}

เราสามารถ import class เข้ามาได้โดยใช้คำสั่ง #:import Name package.ClassName ในKivy ซึ่งจะมีความหมายเหมือนกับ from package.ClassName import ClasName as Name ใน Python
ในส่วนต่อไปเราจะทำการสร้าง bind event ใน ภาษา Kivy โดยการทำใน Kivy นั้นจะทำการเพิ่ม event เข้าไปในส่วนที่เจาะจงจะแอดเข้าไปได้ง่ายกว่ายกตัวอย่างเช่นเราต้องการเพิ่มการกดเข้าไปใน DragableWidget ส่วนประกอบทั้งหมดที่มีอันนี้ก็จะได้รับการ implement ไปและเราจะมาเริ่มทำการเพิ่ม event เข้าไปใน Button และ ToggleButton โดยก่อนอื่นต้องทำการสร้างไฟล์ generaloption.kv ขึ้นมาใหม่ก่อน

โค้ดในไฟล์ generaloption.kv

#:import generaloptions generaloptions
<GeneralOptions>:
  orientation: 'horizontal'
  padding: 2
  Button:
    text: 'Clear'
    on_press: root.clear(*args)
  Button:
    text: 'Remove'
    on_release: root.remove(*args)
  ToggleButton:
    text: 'Group'
    on_state: root.group(*args)
  Button:
    text: 'Color'
    on_press: root.color(*args)
  ToggleButton:
    text: 'Gestures'
    on_state: root.gestures(*args)

 จะเห็นได้ว่า button มี event เพิ่มมา 2 อันได้แก่ on_press และ on_release โดยรูปแบบการทำงานของมันนั้นคล้ายกับ on_touch_down และ on_touch_up อย่างไรก็ตามในกรณีนี้เราไม่จำเป็นต้องกังวลที่จะเรียกใช้เมทอด collide_point เพราะเราใช้ on_press ที่ clear button และ color button และ on_release ที่ remove button ซึ่งมันจะไม่ชนกันอยู่แล้วและให้เราสร้าง generaloptions.py ขึ้นมา

โค้ดในไฟล์ generaloptions.py คือ

from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty, ListProperty
class GeneralOptions(BoxLayout):
    group_mode = False
    translation = ListProperty(None)
    def clear(self, instance):
        self.drawing_space.clear_widgets()
    def remove(self, instance):
        ds = self.drawing_space
        if len(ds.children) > 0:
            ds.remove_widget(ds.children[0])
    def group(self, instance, value):
        if value == 'down':
            self.group_mode = True
            else:
                self.group_mode = False
                self.unselect_all()
    def color(self, instance):
        pass
    def gestures(self, instance, value):
        pass
    def unselect_all(self):
        for child in self.drawing_space.children:
            child.unselect()
    def on_translation(self,instance,value):
        for child in self.drawing_space.children:
            if child.selected:
                child.translate(*self.translation)

แล้วสุดท้ายเค้าก็จะให้ตัวอย่างโค้ดมาให้สร้างไฟล์ .py ของ ทุกไฟล์แล้วก็เสร็จเรียบร้อยสามารถใช้งานได้

ไม่มีความคิดเห็น:

แสดงความคิดเห็น