1. 理解 kivy 坐標系統
上一節中,咪博士帶大家實現了畫板程序的基礎框架,以及一個基本的自定義窗口部件(widget)。在上一節的末尾,咪博士留了一道關于 kivy 坐標系統的思考題給大家。通過點擊窗口的 4 個角落,觀察相應的控制臺輸出,我們可以推斷出 kivy 的坐標原點位于窗口的左下角,x 軸正方向為水平向右,y 軸正方向為豎直向上。這和我們中學數學中常見的平面直角坐標系是一模一樣的。
2. 繪制圓點
了解了 kivy 的坐標系統,本節咪博士將教大家實現簡易畫板的核心功能:繪圖。
重點需要修改的是 MyPaintWidget 的 on_touch_down 方法,同時還要在程序開頭(第 3 行)添加導入顏色和畫圖的函數。修改后的代碼如下:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
class MyPaintApp(App):
def build(self):
return MyPaintWidget()
if __name__ == '__main__':
MyPaintApp().run()
運行程序,當用鼠標左鍵在窗口上點擊的時候,程序會在鼠標點擊的位置繪制出一個黃色的圓點。
第 8 行 with self.canvas:,使用 with 語句進入自定義窗口部件 (MyPaintWidget) 的畫布 (canvas) 上下文。窗口部件 (widget) 的畫布 (canvas) 對應窗口部件在屏幕上的顯示區域,我們可以在上面繪制各種圖形。執行第 8 行代碼之后,后續的繪圖語句就會在這個畫布上繪制出各種圖形了。with 語句還能確保當我們退出畫布上下文的時候,程序自動清理與畫布有關的內部狀態并釋放相應的資源。
第 9 行 Color(1,1,0)將畫筆的顏色設置為黃色。Color 采用 RGB(紅、綠、藍)三原色來表示顏色,每個顏色分量的取值為 [0, 1] 之間。這里我們混合紅色和綠色(第 1, 2 個參數為 1),剔除藍色(第 3 個參數為 0),根據三原色的原理,我們將得到黃色。設置好顏色之后,后續的繪圖都將采用這個顏色,直到你用 Color 函數再次改變顏色。這就好像你用畫筆蘸上黃色的顏料(調用 Color 函數),你隨后畫出的圖案就都是黃色的,一直到你再蘸其他的顏料(再次調用 Color 函數),改變畫筆的顏色。
第 10 行 d=30.設置圓的直徑,后續的代碼將根據變量 d 的值來畫圓。如果,我們想改變圓的大小,只要修改變量 d 的值就可以了,這也是將圓的直徑保存到變量中,給程序帶來的靈活性。
第 11 行 Ellipse(pos=(touch.x - d/2,touch.y - d/2),size=(d,d)) 調用Ellipse 函數在鼠標點擊的位置,按照指定的直徑畫圓。Ellipse 函數中,圓的位置用圓的外切正方形來表示。其中,第 1 個參數 pos 表示外切正方形左下角的坐標(x, y),第 2 個參數 size 表示外切正方形的大?。▽挕⒏撸?。我們想要讓圓心落在鼠標點擊的位置,因此,對應的外切正方形左下角坐標為 (touch.x - d/2,touch.y - d/2)
3. 繪制線條
接著,我們要實現拖拽鼠標繪制線條的功能。代碼如下:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
return MyPaintWidget()
if __name__ == '__main__':
MyPaintApp().run()
程序運行后的效果像下面這樣
第 3 行 from kivy.graphics import Color, Ellipse, Line我們導入函數 Line 用于繪制線條。函數 Line 接受一個由一系列點的坐標所構成的列表,然后依次在相鄰 2 點之間繪制線條。
第 12 行中的 touch.ud 是一個 Python 字典 (dict),我們可以用它來存儲與 touch 事件相關的數據。整個第 12 行 touch.ud['line']=Line(points=(touch.x,touch.y)) 表示的意思是,當鼠標按下時(觸發 on_touch_down 事件),以鼠標點擊的位置 (touch.x, touch.y) 為起點繪制線條(調用 Line 函數),然后將該線條保存到 touch.ud 字典中(對應的 key 值為 ‘line’)。由于,鼠標點擊只能產生 1 個點,而 1 個點是沒有辦法繪制線條的,所以單純的鼠標點擊是無法在屏幕上看到任何線條的。但是,這里確實產生了一個線條,并且我們將它保存到 touch.ud[‘line’] 中,隨后的代碼將繼續往這個線條中添加坐標點,而一系列點的連線就可以顯示出來了。
第 14 行 def on_touch_move(self,touch):添加了一個新的方法 on_touch_move。當用戶拖拽鼠標時,將觸發該函數(執行該函數中的代碼)。一次鼠標拖拽通常會連續多次觸發 on_touch_move 方法,相當于將一次移動拆解成很多個微小的移動,而每一次移動的位置則通過 touch 參數傳遞給 on_touch_move 方法。
第 15 行 touch.ud['line'].points+=[touch.x,touch.y] 將鼠標拖拽產生的坐標點,添加到保存在 touch.ud[‘line’] 中的線條中。
原文鏈接:http://www.ipaomi.com/2017/11/16/kivy-中文教程-實例入門-簡易畫板-simple-paint-app:2-實現繪圖功能/