2025-09-02
Python
00
请注意,本文编写于 183 天前,最后修改于 182 天前,其中某些信息可能已经过时。

目录

图形绘制
页面背景
基本图形绘制
矩形
椭圆
半圆及多边形
多边形
点和线
Cancas 属性

只是个人学习的时候的一些笔记,如果有什么错误的地方还请各位勿喷,手下留情,期待您的指正。 定期会更新文章到blog.sea-whales.cn 我的个人网站中,有兴趣的小伙伴可以进来看看

图形绘制

页面背景

看过布局的朋友们,一定发现了,在创建一个widget控件后,为布局设置背景色或者经常会有一个with self.canvas并且加了几个属性和绑定了事件,这些其实是我们在生成一个控件后,Kivy自动生成的一个类似画布的。我们通过对画布的更改可以设置颜色、尺寸、背景图等。 这里说明一下,canvas 学过HTML5的同学肯定觉得眼熟,但是实际两个是不相同的。 HTML的Canvas的定义是:

HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。 画布是一个矩形区域,您可以控制其每一像素。 canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

而Kivy的Canvas本质是一组在坐标空间的指令容器,可以理解成坐标空间中一个无限的绘画板,通过添加指令来绘制图形。 我们先来使用纯色进行设置背景。

python
# !/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里面新加一个画布,对画布初始化为白色背景。如果我们要填满整个窗口只需要在初始化好画布之后,对画布进行大小重定义即可实现覆盖。参考如下:

python
# !/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文件配合的情况下如何实现以上样子

python
# !/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文件

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代码就好:

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里,每个小部件和布局基本都有他的CanvasCanvas.beforecanvas.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.beforecanvas.after属性,用法的话基本和canvas一致。只是在运行顺序上的优先级不同。 大概顺序是:

  • canvas.before > canvas > widget(canvas.befor,canvas,canvas.after) > canvas.after

以上就是图像绘制中画布Canvas的属性使用以及优先级,若有误,望指正~

本文作者:sea-whales

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!