跳到主要内容

画布 Canvas

Canvas是一种使用一组基本图形或"形状"(如线条、弧线、路径和文本)来绘制任意图形的控件。

示例

在线示例

基本用法

import math

import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
stroke_paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE)
fill_paint = ft.Paint(style=ft.PaintingStyle.FILL)
cp = cv.Canvas(
[
cv.Circle(100, 100, 50, stroke_paint),
cv.Circle(80, 90, 10, stroke_paint),
cv.Circle(84, 87, 5, fill_paint),
cv.Circle(120, 90, 10, stroke_paint),
cv.Circle(124, 87, 5, fill_paint),
cv.Arc(70, 95, 60, 40, 0, math.pi, paint=stroke_paint),
],
width=float("inf"),
expand=True,
)

page.add(cp)

ft.app(main)

Path形状示例

import math

import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
cp = cv.Canvas(
[
cv.Path(
[
cv.Path.MoveTo(25, 25),
cv.Path.LineTo(105, 25),
cv.Path.LineTo(25, 105),
],
paint=ft.Paint(
style=ft.PaintingStyle.FILL,
),
),
cv.Path(
[
cv.Path.MoveTo(125, 125),
cv.Path.LineTo(125, 45),
cv.Path.LineTo(45, 125),
cv.Path.Close(),
],
paint=ft.Paint(
stroke_width=2,
style=ft.PaintingStyle.STROKE,
),
),
],
width=float("inf"),
expand=True,
)

page.add(cp)

ft.app(main)

贝塞尔曲线

import math

import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
cp = cv.Canvas(
[
cv.Path(
[
cv.Path.MoveTo(75, 25),
cv.Path.QuadraticTo(25, 25, 25, 62.5),
cv.Path.QuadraticTo(25, 100, 50, 100),
cv.Path.QuadraticTo(50, 120, 30, 125),
cv.Path.QuadraticTo(60, 120, 65, 100),
cv.Path.QuadraticTo(125, 100, 125, 62.5),
cv.Path.QuadraticTo(125, 25, 75, 25),
],
paint=ft.Paint(
stroke_width=2,
style=ft.PaintingStyle.STROKE,
),
),
cv.Path(
[
cv.Path.SubPath(
[
cv.Path.MoveTo(75, 40),
cv.Path.CubicTo(75, 37, 70, 25, 50, 25),
cv.Path.CubicTo(20, 25, 20, 62.5, 20, 62.5),
cv.Path.CubicTo(20, 80, 40, 102, 75, 120),
cv.Path.CubicTo(110, 102, 130, 80, 130, 62.5),
cv.Path.CubicTo(130, 62.5, 130, 25, 100, 25),
cv.Path.CubicTo(85, 25, 75, 37, 75, 40),
],
100,
100,
)
],
paint=ft.Paint(
gradient=ft.PaintRadialGradient(
ft.Offset(150, 150), 50, [ft.colors.PINK_100, ft.colors.PINK]
),
style=ft.PaintingStyle.FILL,
),
),
],
width=float("inf"),
expand=True,
)

page.add(cp)

ft.app(main)

绘制文本

import math

import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
cp = cv.Canvas(
[
cv.Text(0, 0, "Just a text"),
cv.Circle(200, 100, 2, ft.Paint(color=ft.colors.RED)),
cv.Text(
200,
100,
"Rotated",
ft.TextStyle(weight=ft.FontWeight.BOLD, size=30),
spans=[
ft.TextSpan(
"around top_center",
ft.TextStyle(italic=True, color=ft.colors.GREEN, size=20),
)
],
alignment=ft.alignment.top_center,
rotate=math.pi * 0.15,
),
cv.Circle(400, 100, 2, ft.Paint(color=ft.colors.RED)),
cv.Text(
400,
100,
"Rotated around top_left",
ft.TextStyle(size=20),
alignment=ft.alignment.top_left,
rotate=math.pi * -0.15,
),
cv.Circle(600, 200, 2, ft.Paint(color=ft.colors.RED)),
cv.Text(
600,
200,
"Rotated around center",
ft.TextStyle(size=20),
alignment=ft.alignment.center,
rotate=math.pi / 2,
),
cv.Text(
300,
400,
"Limited to max_width and right-aligned.\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
text_align=ft.TextAlign.RIGHT,
max_width=400,
),
cv.Text(
200,
200,
"WOW!",
ft.TextStyle(
weight=ft.FontWeight.BOLD,
size=100,
foreground=ft.Paint(
gradient=ft.PaintLinearGradient(
(200, 200),
(300, 300),
colors=[ft.colors.YELLOW, ft.colors.RED],
),
stroke_join=ft.StrokeJoin.ROUND,
stroke_cap=ft.StrokeCap.ROUND,
),
),
),
cv.Text(
200,
200,
"WOW!",
ft.TextStyle(
weight=ft.FontWeight.BOLD,
size=100,
foreground=ft.Paint(
color=ft.colors.PINK,
stroke_width=6,
style=ft.PaintingStyle.STROKE,
stroke_join=ft.StrokeJoin.ROUND,
stroke_cap=ft.StrokeCap.ROUND,
),
),
),
],
width=float("inf"),
expand=True,
)

page.add(cp)

ft.app(main)

自由绘图工具 - 带手势检测的画布

import flet as ft
import flet.canvas as cv

class State:
x: float
y: float

state = State()

def main(page: ft.Page):
page.title = "Flet Brush"

def pan_start(e: ft.DragStartEvent):
state.x = e.local_x
state.y = e.local_y

def pan_update(e: ft.DragUpdateEvent):
cp.shapes.append(
cv.Line(
state.x, state.y, e.local_x, e.local_y, paint=ft.Paint(stroke_width=3)
)
)
cp.update()
state.x = e.local_x
state.y = e.local_y

cp = cv.Canvas(
[
cv.Fill(
ft.Paint(
gradient=ft.PaintLinearGradient(
(0, 0), (600, 600), colors=[ft.colors.CYAN_50, ft.colors.GREY]
)
)
),
],
content=ft.GestureDetector(
on_pan_start=pan_start,
on_pan_update=pan_update,
drag_interval=10,
),
expand=False,
)

page.add(
ft.Container(
cp,
border_radius=5,
width=float("inf"),
expand=True,
)
)


ft.app(main)

Canvas属性

resize_interval

on_resize事件的采样间隔,以毫秒为单位。默认值为0,即在每次更改时调用on_resize

shapes

要绘制在画布上的Shape对象(详见下文)的列表。

Canvas事件

on_resize

当画布的大小发生变化时触发。

事件对象eCanvasResizeEvent类的实例,具有以下字段:

  • width - 画布的新宽度。
  • height - 画布的新高度。

Arc形状属性

绘制一个按比例缩放以适应给定矩形的弧。

它从椭圆的start_angle弧度开始,绕椭圆绕start_angle + sweep_angle弧度,其中零弧度是椭圆右侧与通过矩形中心的水平线相交的点,正角度顺时针绕椭圆。如果use_centerTrue,则弧段闭合回中心,形成一个圆扇区。否则,弧段不闭合,形成一个圆段。

[图片] - https://api.flutter.dev/flutter/dart-ui/Canvas/drawArc.html

x

弧的左上角点的x轴坐标。

y

弧的左上角点的y轴坐标。

width

包含弧的椭圆的矩形的宽度。

height

包含弧的椭圆的矩形的高度。

start_angle

从哪个角度开始绘制弧。

sweep_angle

弧的长度(弧度)。

use_center

如果use_centerTrue,则弧段闭合回中心,形成一个圆扇区。否则,弧段不闭合,形成一个圆段。

paint

用于绘制弧的样式。该属性的值是ft.Paint的实例。

Circle形状属性

绘制一个圆。

x

圆心点的x轴坐标。

y

圆心点的y轴坐标。

radius

圆的半径。

paint

用于绘制圆的样式。该属性的值是ft.Paint的实例。

Color形状属性

将给定的color绘制到画布上,应用给定的blend_mode,其中给定的颜色是源,背景是目标。

color

要绘制到画布上的颜色

blend_mode

要应用的混合模式。

请参阅ShaderMask.blend_mode以获取可能的混合模式值。

Fill形状属性

使用给定的Paint填充画布。

要使用纯色和混合模式填充画布,请考虑使用Color形状。

paint

用于填充画布的样式。该属性的值是ft.Paint的实例。

Line形状属性

使用给定的画笔在给定的点之间绘制一条线。该线是描边的,忽略Paint.style的值。

x1

线的起点的x轴坐标。

y1

线的起点的y轴坐标。

x2

线的终点的x轴坐标。

y2

线的终点的y轴坐标。

paint

用于绘制线条的样式。该属性的值是ft.Paint的实例。

Oval形状属性

使用给定的Paint绘制填充给定矩形的轴对齐椭圆。填充或描边(或两者)的方式由Paint.style控制。

x

椭圆的左上角点的x轴坐标。

y

椭圆的左上角点的y轴坐标。

width

包含椭圆的矩形的宽度。

height

包含椭圆的矩形的高度。

paint

用于绘制椭圆的样式。该属性的值是 ft.Paint 的实例。

Path 形状属性

使用给定的 paint 绘制路径。

路径的填充或描边(或两者)由 Paint.style 控制。如果路径被填充,那么其中的子路径会被隐式关闭(参见 Path.Close)。

elements

路径元素的列表:

Path.MoveTo(x, y)

从给定点(xy)开始一个新的子路径。

Path.LineTo(x, y)

从当前点到给定点(xy)添加一条直线段。

Path.QuadraticTo(cp1x, cp2y, x, y, w)

添加一个贝塞尔曲线段,它从当前点到给定点(xy)曲线,使用控制点 (cp1xcp1y) 和权重 w。如果权重大于 1,那么曲线是一个双曲线;如果权重等于 1,则是一个抛物线;如果小于 1,则是一个椭圆。

Path.CubicTo(cp1x, cp1y, cp2x, cp2y, x, y)

添加一个立方贝塞尔曲线段,它从当前点到给定点(xy)曲线,使用控制点 (cp1xcp1y) 和 (cp2xcp2y)。

Path.SubPath(elements, x, y)

将由 elements 描述的子路径添加到给定点(xy)。

Path.Arc(x, y, width, height, start_angle, sweep_angle)

添加一个新的子路径,其中包含一段弧,该弧沿着以 xy 为左上角,并具有 widthheight 维度的矩形的边界。弧从椭圆开始的 start_angle 弧度开始,绕着椭圆一直到 start_angle + sweep_angle 弧度结束,其中 0 弧度是椭圆右侧交叉矩形中心的水平线上的点,正角度按顺时针方向绕椭圆。

Path.ArcTo(x, y, radius, rotation, large_arc, clockwise)

附加最多四个权重,以描述具有 radius 的椭圆,并且被 rotation(以度为单位,顺时针)旋转。

第一个曲线从路径中的最后一个点开始,最后一个点在路径结束于 xy 之前。曲线根据 clockwise(布尔值)和 large_arc(布尔值)决定路径方向,以使扫描角度始终小于 360 度。

如果任一半径为零或路径的最后一个点(xy),则附加一个简单的线。如果两个都大于零但太小而无法描述弧,则将半径缩放以适应最后的路径点。

Path.Oval(x, y, width, height)

添加一个新的子路径,该路径由填充给定矩形的椭圆形成。

Path.Rect(x, y, width, height, border_radius)

将矩形添加为新的子路径。

Path.Close

关闭最后的子路径,就像从当前点到子路径的第一个点画一条直线一样。

paint

用于绘制路径的样式。该属性的值是 ft.Paint 的实例。

Points 形状属性

根据给定的 point_mode 绘制一系列点。

points

描述点的 ft.Offset 列表。

point_mode

在绘制一组点时如何解释点列表。值的类型为 ft.PointMode

  • POINTS - 将每个点分开绘制。如果 Paint.stroke_capStrokeCap.ROUND,那么每个点将以 Paint.stroke_width 的直径绘制为圆,填充如 Paint 描述的(忽略 Paint.style)。否则,每个点将绘制为边长为 Paint.stroke_width 的轴对齐正方形,填充如 Paint 描述的(忽略 Paint.style)。
  • LINES - 将每个两个点的序列绘制为线段。如果点数为奇数,则最后一个点将被忽略。线段将如 Paint 描述的绘制(忽略 Paint.style)。
  • POLYGON - 将点序列绘制为一条线。线段将如 Paint 描述的绘制(忽略 Paint.style)。

paint

用于绘制点的样式。该属性的值是 ft.Paint 的实例。

Rect 形状属性

绘制一个矩形。

x

矩形左上角的 x 轴坐标。

y

矩形左上角的 y 轴坐标。

width

矩形的宽度。

height

矩形的高度。

border_radius

矩形的边框半径,类型为 ft.BorderRadius

paint

用于绘制矩形的样式。该属性的值是 ft.Paint 的实例。

Shadow 形状属性

为表示给定材质 elevationpath 绘制阴影。

如果遮挡对象不是不透明的,则 transparent_occluder 参数应为 True

path

描述路径的 Path.PathElement 对象列表。

color

阴影

颜色

elevation

阴影的高程。

transparent_occluder

如果遮挡对象不是不透明的,则为 True。默认为 False

Text 形状属性

在给定点 (x, y) 用 style 绘制 text

x

文本的 alignment 点的 x 轴坐标。

y

文本的 alignment 点的 y 轴坐标。

text

要绘制的文本。

style

用于绘制 textspans 的文本样式。该值是 ft.TextStyle 类的实例。

spans

用于构建富文本段落的 ft.TextSpan 对象列表。

alignment

确定文本矩形的位置和旋转中心的点。

值的类型为 ft.Alignment。默认值为 ft.alignment.top_left

text_align

文本水平对齐方式。支持的值请参见 Text.text_align 属性。

max_lines

要绘制的最大行数。超过此数的行将被忽略。例如,如果 max_lines 为 1,则只绘制一行。如果 max_linesNone,但省略号不为 None,则超出宽度约束的第一行之后的行将被忽略。

max_width

绘制文本的最大宽度。默认值为 None - 无限。

ellipsis

用于省略溢出文本的字符串。

rotate

以弧度为单位的文本旋转。文本围绕由 alignment 确定的点旋转。请参阅上面的代码示例。

Paint 属性

在画布上绘制形状时要使用的样式描述。

anti_alias

是否对画布上绘制的线条和图像应用抗锯齿。默认为 True

blend_mode

备注

该属性尚未实现,保留供将来使用。

绘制形状或合成图层时应用的混合模式。

默认为 BlendMode.SRC_OVER

请参阅 ShaderMask.blend_mode 以获取可能的混合模式值。

blur_image

备注

该属性尚未实现,保留供将来使用。

在画布上绘制图像时进行模糊处理。

有关更多信息,请参阅 Container.blur

color

在绘制形状的填充或描边时要使用的颜色。默认为不透明的黑色。

gradient

配置渐变填充。其值是以下类之一的实例:

  • PaintLinearGradient
  • PaintRadialGradient
  • PaintSweepGradient

Path形状属性

PaintLinearGradient

cv.Rect(
10,
10,
100,
100,
5,
ft.Paint(
gradient=ft.PaintLinearGradient(
(0, 10), (0, 100), colors=[ft.colors.BLUE, ft.colors.YELLOW]
),
style=ft.PaintingStyle.FILL,
),
)

PaintLinearGradient类具有以下属性:

  • begin - Offset类的实例。渐变的起始位置。
  • end - Offset类的实例。渐变的结束位置。
  • colors - 渐变在每个位置应该具有的颜色。如果stops参数为非空,则该列表的长度必须与stops参数的长度相同。该列表至少必须包含两种颜色(否则,它不是渐变!)。
  • stops - 一个从0.0到1.0的值的列表,表示沿着渐变的分数位置。如果stops参数为非空,则该列表的长度必须与colors参数的长度相同。如果第一个值不是0.0,则会隐含一个位置为0.0且颜色为colors列表中的第一个颜色的停止点。如果最后一个值不是1.0,则会隐含一个位置为1.0且颜色为colors列表中的最后一个颜色的停止点。
  • tile_mode - 渐变在beginend之前和之后的平面上如何平铺。该值是GradientTileMode枚举,支持的值有:CLAMP(默认值)、DECALMIRRORREPEATED。更多信息请参阅这里
  • rotation - 渐变的旋转角度,以渐变边界框的中心点为中心点,单位为弧度

更多信息:

PaintRadialGradient

cv.Circle(
60,
170,
50,
ft.Paint(
gradient=ft.PaintRadialGradient(
(60, 170), 50, colors=[ft.colors.YELLOW, ft.colors.BLUE]
),
style=ft.PaintingStyle.FILL,
),
)

PaintRadialGradient类具有以下属性:

  • center - Offset类的实例。渐变的中心位置。
  • radius - 渐变的半径。
  • colorsstopstile_moderotation - 参见线性渐变中对这些属性的描述。
  • focal - 渐变的焦点。如果指定了焦点,则渐变将沿着从center到焦点的向量聚焦。
  • focal_radius - 渐变焦点的半径,作为绘制框最短边的一部分。例如,如果在宽度为100.0像素、高度为200.0像素的框上绘制径向渐变,则半径为1.0将使1.0的停止点距离焦点100.0像素。

更多信息:

PaintSweepGradient

cv.Path(
[
cv.Path.MoveTo(60, 230),
cv.Path.LineTo(110, 330),
cv.Path.LineTo(10, 330),
cv.Path.Close(),
],
ft.Paint(
gradient=ft.PaintSweepGradient(
(60, 280),
colors=[ft.colors.YELLOW, ft.colors.BLUE],
start_angle=0,
end_angle=math.pi * 2,
),
stroke_width=5,
stroke_join=ft.StrokeJoin.ROUND,
style=ft.PaintingStyle.STROKE,
),
)

PaintSweepGradient类具有以下属性:

  • center - 渐变的中心位置。
  • colorsstopstile_moderotation - 参见线性渐变中对这些属性的描述。
  • start_angle - 渐变的起始角度(以弧度为单位)。默认值为0.0。
  • end_angle - 渐变的结束角度(以弧度为单位)。默认值为math.pi * 2。
  • rotation - 渐变的旋转角度(以弧度为单位)。

更多信息:

stroke_cap

style设置为PaintingStyle.STROKE时,线段末端的样式。

该值是ft.StrokeCap枚举的一个实例:

  • BUTT(默认值)- 线段的末端以平直的边缘结束,没有延伸。
  • ROUND - 线段的末端以半圆形的延伸结束。
  • SQUARE - 线段的末端以半个正方形的延伸结束。这类似于将每个线段的末端延长半个线段宽度(由Paint.stroke_width给定)。

stroke_join

线段之间连接的样式。

这适用于style设置为PaintingStyle.STROKE时绘制的路径,不适用于使用canvas.Points绘制的点线。

默认值为StrokeJoin.MITER,即尖锐的拐角。

该值是ft.StrokeJoin枚举的一个实例:

  • MITER(默认值)- 线段之间的连接形成尖锐的拐角。
  • ROUND - 线段之间的连接是半圆形的。
  • BEVEL - 线段之间的连接将线段的末端的角连接起来,形成斜角外观。

有关详细信息,请参阅Flutter文档中的StrokeJoin枚举

stroke_miter_limit

当连接设置为StrokeJoin.MITER且样式设置为PaintingStyle.STROKE时,线段上的斜接限制。如果超过此限制,则将绘制StrokeJoin.BEVEL连接。如果线段之间的角度发生动画变化,这可能会导致路径的角出现一些"弹跳"效果。

该限制表示为斜接的长度限制。

默认值为4.0。将限制设置为0将始终使用StrokeJoin.BEVEL连接。

stroke_width

当样式设置为PaintingStyle.STROKE时,边缘的宽度。宽度以与路径方向垂直的逻辑像素为单位。

默认值为0.0,对应于毛细线宽度。

stroke_dash_pattern

虚线的偏移和长度的循环数组。

例如,数组[5, 10]将生成长度为5像素的虚线,后面跟着长度为10像素的空白间隔。数组[5, 10, 5]将生成长度为5像素的虚线,后面跟着长度为10像素的空白间隔,再后面是长度为5像素的虚线,以此类推。

style

绘制形状的内部、边缘或两者。

该值是ft.PaintingStyle枚举的一个实例:

  • FILL(默认值)- 将Paint应用于形状的内部。例如,应用于canvas.Circle形状时,将绘制一个给定大小的圆盘。
  • STROKE - 将Paint应用于形状的边缘。例如,应用于canvas.Circle形状时,将绘制一个给定大小的圆环。边缘上绘制的线的宽度由Paint.stroke_width属性给定。