只是个人学习的时候的一些笔记,如果有什么错误的地方还请各位勿喷,手下留情,期待您的指正。
定期会更新文章到www.sea-whales.cn我的个人网站中,有兴趣的小伙伴可以进来看看
图形绘制
页面背景
看过布局的朋友们,一定发现了,在创建一个widget控件后,为布局设置背景色或者经常会有一个with self.canvas
并且加了几个属性和绑定了事件,这些其实是我们在生成一个控件后,Kivy自动生成的一个类似画布的。我们通过对画布的更改可以设置颜色、尺寸、背景图等。
这里说明一下,canvas 学过HTML5的同学肯定觉得眼熟,但是实际两个是不相同的。
HTML的Canvas的定义是:
HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。
画布是一个矩形区域,您可以控制其每一像素。
canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
而Kivy的Canvas本质是一组在坐标空间的指令容器,可以理解成坐标空间中一个无限的绘画板,通过添加指令来绘制图形。
我们先来使用纯色进行设置背景。
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.graphics import Rectangle, Color
class BoxLayoutWidget(BoxLayout):
def __init__(self, **kwargs):
super(BoxLayoutWidget, self).__init__(**kwargs)
with self.canvas:
Color(1, 1, 1, 1)
Rectangle(pos=self.pos, size=self.size)
class BoxLayoutApp(App):
def build(self):
return BoxLayoutWidget()
if __name__ == '__main__':
BoxLayoutApp().run()
运行上面代码可以发现,在布局中,左下角有一块100*100的白色小方块,这时候我们就完成了基础的颜色设置,但是我们需要把白色填满整个方块。其实以上代码的操作是初始化一个BoxLayou然后,初始化后其实一个黑色的背景,然后在with里面新加一个画布,对画布初始化为白色背景。如果我们要填满整个窗口只需要在初始化好画布之后,对画布进行大小重定义即可实现覆盖。参考如下:
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.graphics import Rectangle, Color
class BoxLayoutWidget(BoxLayout):
def __init__(self, **kwargs):
super(BoxLayoutWidget, self).__init__(**kwargs)
with self.canvas:
# 设置颜色值,通常百分比形式比较难把握,我们可以选择将rgb的色值除255,
# 例如:海蓝宝石(#7FFFD4)色的rgb的色值是(127,255,212)写成Kivy的Color就写成
# Color(127/255,255/255,212/255,0),最后一个值是设置透明度的一般选择0~1之间的值。
# 0不透明,1为透明
Color(127 / 255, 255 / 255, 212 / 255, 1)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.bind(pos=self.update_rect, size=self.update_rect)
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
class BoxLayoutApp(App):
def build(self):
return BoxLayoutWidget()
if __name__ == '__main__':
BoxLayoutApp().run()
老样子,我们看看KV文件配合的情况下如何实现以上样子
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
class BoxLayoutWidget(BoxLayout):
def __init__(self, **kwargs):
super(BoxLayoutWidget, self).__init__(**kwargs)
class ColorApp(App):
def build(self):
return BoxLayoutWidget()
if __name__ == '__main__':
ColorApp().run()
kv文件
<BoxLayoutWidget>
canvas:
Color:
rgba: [127 / 255, 255 / 255, 212 / 255, 1]
Rectangle:
size: self.size
pos: self.pos
还可以在有底色的情况下,使用背景图片。
只需把前面Python代码中19行新增一个参数即可如下:
self.rect = Rectangle(pos=self.pos, size=self.size, source='canvas_image.jpg')
或者kv文件中Rectangle
下新增source: 'canvas_image.jpg'
,其中canvas_image.jpg
是图片名称和地址。
基本图形绘制
前面,我们使用纯色背景以及使用图片来将Canvas
这个画布进行上色和调整等,接下来我们试试在画好的画布中进行简单图形的绘制,比如。矩形、椭圆等
矩形
其实我们前面也一直在画这个矩形,只是有的部分把他填充了。
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.uix.relativelayout import RelativeLayout
from kivy.app import App
class RelativeWidget(RelativeLayout):
def __init__(self, **kwargs):
super(RelativeWidget, self).__init__(**kwargs)
class DrawRectangleApp(App):
def build(self):
return RelativeWidget()
if __name__ == '__main__':
DrawRectangleApp().run()
drawrectangle.kv
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Rectangle:
size: self.width*0.2, self.height*.15
pos: self.x+10, self.y+10
椭圆
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.uix.relativelayout import RelativeLayout
from kivy.app import App
class RelativeWidget(RelativeLayout):
def __init__(self, **kwargs):
super(RelativeWidget, self).__init__(**kwargs)
class DrawEllipseApp(App):
def build(self):
return RelativeWidget()
if __name__ == '__main__':
DrawEllipseApp().run()
drawellipse.kv
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Ellipse:
size: self.width*.35, self.height*.35
pos: self.x+250, self.top-400
半圆及多边形
其实半圆的画法和椭圆基本一致。只是增加了三个新属性。
angle_start
: 开始线角度,开始方向与y轴的角度。angle_end
: 结束线角度,结束方向与y轴的角度。一般angle_end
的大小要大于angle_start
,若不大于则需要加 360° ,此时Kivy会顺时针画图形。否则则是逆时针画图形。egments
: 多边形的边数,可以用来画三角形,六边形等形状。
例如,我们改下前面的椭圆,在它旁边加多一个六边形,一个三角形以及一个扇形还有正圆。Python代码我们继续使用椭圆的代码。改下Kv代码就好:
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Ellipse: # 正圆
size: self.width*0.20, self.width*0.20
pos: self.x+20, self.top-200
Ellipse: # 正六边形
size: self.height*0.25, self.height*0.25
pos: self.x+200, self.top-200
segments: 6
Ellipse: # 超过180°的顺时针扇形
size: self.width*0.25, self.height*.25
pos: self.x+400, self.top-200
angle_start: 120
angle_end: 420
Ellipse: # 正三角
size: self.height*.25, self.height*.25
pos: self.x+400, self.top-400
segments: 3
Ellipse: # 正半圆
size: self.height*0.25, self.height*.25
pos: self.x+200, self.top-400
angle_start: 0
angle_end: 180
Ellipse: # 椭圆
size: self.height*0.30, self.width*.15
pos: self.x+20, self.top-400
多边形
前面使用了画圆的方式使用参数segments
来画多边形,这些多变形画出来它的边长是随着圆的尺寸决定的,长度是不能自己决定的。
Kivy还提供了一种方式,用于指定各边的顶点坐标,可以绘制特殊边的多边形,但是值支持四个坐标点,可用于菱形、平行四边形、梯形等。
一样,我们值更改Kv文件如下:
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Quad:
points: 400,250, 640,280, 480,500, 380,520 # 设置顶点坐标。 按X轴,Y轴的顺序读取顶点坐标。
Quad
中的points
会按照x轴,y轴的的顺序,读取点的位置,并且在画布canvas
上绘制一个多边形。
点和线
kv文件
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Line:
points: 310,350, 310,280, 360,350, 510,350
Point:
points:300,200, 300,400
pointsize: 5
其实就像数学里面理解的,所有的线是由无数个点挨着排列形成的,同理面是由线挨着排列形成的。我们也可以用点和线画前面的图形。
例如:
<RelativeWidget>
canvas:
Color:
rgba: [1,1,1,1]
Line: # 线
points: 110,150, 310,80
Point: # 点
points:100,200, 180,260
pointsize: 5 # 点大小
Line: # 椭圆
ellipse: 210,320, 80,60, 120,420,180
width: 2 # 线宽
Line: # 圆
circle: 350,350, 40,0, 360,180
width: 1.5
Line: # 矩形
rectangle: 410,310, 80, 70
Line:
points: 510,310, 540,390, 590,320
close: True # 是否闭合
KV中Line对应参数说明:
- ellipse:210, 320 表示椭圆的位置;80, 60 代表椭圆的宽和长;120, 420,180分别对应: angel_start, angel_end, segments.
- circle: 350,350 表示圆心的位置;40表示圆的半径;0,360,180分别对应: angel_start, angel_end, segments.
- rectangle: 420, 310 表示矩形位置左下角的顶点; 80,70,代表宽高
- points: 510, 310 代表第一个点的位置,以此类推。
Cancas 属性
前面我们已经初步了解了Canvas
画布基本绘制功能。我们来深入了解下他有哪些属性。
在Kivy里,每个小部件和布局基本都有他的Canvas
、Canvas.before
和canvas.after
,其实我们可以将canvas
看作在坐标空间种,一个无限的绘图板,通过添加绘图指令来绘制想要的图形。Kivy的所有部件都是共享一个坐标空间的,且不限于窗口或者屏幕的大小。
我们前面学习的时候也已经试过给画布和小部件设置背景以及显示的颜色。而且我们还能添加不同Instructions
指令来达到不同的页面效果。
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Rectangle, Color
from kivy.graphics.instructions import InstructionGroup
class RelativeWidget(RelativeLayout):
def __init__(self, **kwargs):
super(RelativeWidget, self).__init__(**kwargs)
blue = InstructionGroup()
blue.add(Color(1, 0, 0, .6))
blue.add(Rectangle(pos=self.pos, size=(300,300)))
self.canvas.add(blue)
green = InstructionGroup()
green.add(Color(0, 1, 0, 0.4))
green.add(Rectangle(pos=(300, 300), size=(300, 300)))
self.canvas.add(green)
class AttributeApp(App):
def build(self):
return RelativeWidget()
if __name__ == '__main__':
AttributeApp().run()
通常情况,我们在使用完canvas
画布后,还需使用clear()
方法清除所有加载在画布种的Instructions
指示类型。
我们可以把上面的代码改成with
语法,效果是一致的。
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Rectangle, Color
from kivy.graphics.instructions import InstructionGroup
class RelativeWidgetWith(RelativeLayout):
def __init__(self, **kwargs):
super(RelativeWidgetWith, self).__init__(**kwargs)
with self.canvas:
Color(1, 0, 0, .6)
Rectangle(pos=self.pos, size=(300, 300))
Color(0, 1, 0, 0.4)
Rectangle(pos=(300, 300), size=(300, 300))
class AttributeApp(App):
def build(self):
return RelativeWidgetWith()
if __name__ == '__main__':
AttributeApp().run()
还有一些常用的属性:
Canvas属性 | 说明 |
---|---|
add(Instructions c) | 将Instructions类型的c添加到Canvas中 |
clear() | 删除所有Instructions |
get_group(str groupname) | 返回特定组下所有Instructions |
insert(int index, Instructions c) | 指定位置插入c |
indexof(Instructions c) | 返回c下标 |
length() | 返回canvas的长度 |
remove() | 删除指定的c |
remove_group(str groupname) | 删除该组下所有的c |
在Kivy每个小部件都有属性canvas
,除了这个包括有canvas.before
和canvas.after
属性,用法的话基本和canvas一致。只是在运行顺序上的优先级不同。
大概顺序是:
- canvas.before > canvas > widget(canvas.befor,canvas,canvas.after) > canvas.after
以上就是图像绘制中画布Canvas的属性使用以及优先级,若有误,望指正~