- 前端
- 跨平台
- 桌面应用
- 移动开发
【免费下载链接】flet
Build realtime web, mobile and desktop apps in Python only. No frontend experience required.
导读
CanvasResizeEvent是 Flet 画布(Canvas)在渲染尺寸发生变化时派发的事件对象,它承载画布最新的宽高数据(单位为逻辑像素),通过Canvas.on_resize回调传递给 Python 侧开发者。本文将以 canvasresizeevent.md 为主题,结合源码与官方示例,完整讲解该事件的字段语义、底层触发链路(Python ↔ Flutter)、resize_interval采样节流机制,以及如何用它写出随窗口缩放自动重绘的响应式绘图程序。
一、事件定义:CanvasResizeEvent 是什么
CanvasResizeEvent定义在 canvas.py,它是一个继承自Event["Canvas"]的dataclass,源码 docstring 明确说明:
Event emitted when a
Canvasreports a new rendered size. This event is delivered throughCanvas.on_resizeand carries the latest measured dimensions in logical pixels.
即:当画布实际渲染出来的尺寸发生变化时触发,事件中携带的是逻辑像素(logical pixels)下的最新宽高,与设备像素比(pixel ratio)无关。
字段一览
| 字段 | 类型 | 序列化键(data_field) | 含义 |
|---|---|---|---|
width | float | w | 画布新的宽度(逻辑像素) |
height | float | h | 画布新的高度(逻辑像素) |
注意data_field元数据:Python 侧字段名为width/height,而在底层事件通道(Flutter → Python)中对应的键是w/h。这一点在 Dart 端有直接印证——canvas.dart 触发事件时发送的正是{"w": size.width, "h": size.height},随后由事件解析层依据data_field反序列化填充为CanvasResizeEvent.width与height。
导出路径
CanvasResizeEvent与Canvas一起通过以下路径对外公开,因此业务代码中最常见的导入方式是:
import flet.canvas as cv # cv.CanvasResizeEvent也可直接使用flet.canvas.CanvasResizeEvent。其导出位置可见 flet/canvas/init.py 中的__all__列表。
二、事件从何而来:Canvas.on_resize 与 resize_interval
CanvasResizeEvent不会凭空产生,它由Canvas控件的on_resize事件处理器派发。在 canvas.py 中,与尺寸变化相关的有两个关键成员:
resize_interval: Number = 10 """ Sampling interval in milliseconds for `on_resize` event. Setting to `0` calls :attr:`on_resize` immediately on every change. """ on_resize: Optional[EventHandler[CanvasResizeEvent]] = None """ Called when the size of this canvas has changed. """on_resize:类型为EventHandler[CanvasResizeEvent],回调签名即为(e: CanvasResizeEvent) -> None。当画布尺寸变化时被调用。resize_interval:采样间隔,单位毫秒,默认 10。这是事件触发的节流(throttle)参数——即使底层渲染在连续变化,on_resize最多每resize_interval毫秒派发一次,避免高频重绘导致 Python 侧回调风暴。设置为0则禁用节流,尺寸每次变化都会立即触发。
底层触发链路(源码印证)
从 Flutter 侧实现可以完整还原事件产生的过程。在 canvas.dart 的build方法中:
var resizeInterval = widget.control.getInt("resize_interval", 10)!;Dart 端读取resize_interval(默认 10),随后在自定义画笔FletCustomPainter的onPaintCallback回调中检测尺寸变化:
onPaintCallback: (size) { var now = DateTime.now().millisecondsSinceEpoch; if ((now - _lastResize > resizeInterval && _lastSize != size) || _lastSize.isEmpty) { _lastSize = size; _lastResize = now; widget.control .triggerEvent("resize", {"w": size.width, "h": size.height}); } },这段代码清晰地揭示了三个事实:
- 测量时机:尺寸在每次绘制(paint)时被重新测量,因此能实时反映窗口缩放、布局变化带来的实际渲染尺寸。
- 节流逻辑:只有「距上次派发超过
resize_interval毫秒」且「尺寸确实与上次不同」(或首次绘制)时才触发resize事件,Payload 为{"w": ..., "h": ...}。 - 通道对接:事件名
resize与 Python 侧on_resize对应;Payload 键w/h与CanvasResizeEvent字段的data_field一一对应,完成跨端数据还原。
三、官方示例:随窗口缩放重绘对角线
仓库自带了完整可运行的官方示例 resize/main.py,演示了「监听画布尺寸变化 → 动态更新图形坐标」的标准写法:
import flet as ft import flet.canvas as cv def main(page: ft.Page): def paint_resize(e: cv.CanvasResizeEvent): print("On resize:", e.width, e.height) canvas.shapes[0].x2 = e.width canvas.shapes[0].y2 = e.height canvas.shapes[1].y1 = e.height canvas.shapes[1].x2 = e.width canvas.update() page.add( ft.SafeArea( expand=True, content=ft.Container( width=float("inf"), expand=True, content=( canvas := cv.Canvas( resize_interval=10, on_resize=paint_resize, shapes=[ cv.Line(x1=0, y1=0, x2=100, y2=100), cv.Line(x1=0, y1=100, x2=100, y2=0), ], ) ), ), ) ) if __name__ == "__main__": ft.run(main)拆解其中的关键设计:
- 事件处理器签名:
paint_resize(e: cv.CanvasResizeEvent)接收类型化的事件对象,直接读取e.width、e.height获得画布当前宽高。 - 画布必须可伸展:
Container使用width=float("inf")配合expand=True,SafeArea同样expand=True,使 Canvas 随页面/窗口尺寸变化。从源码看,Canvas.before_update()在expand=True且未显式设置width/height时会自动填充无穷大值(见 canvas.py),从而铺满可用空间——这正是画布「能被 resize」的前提。 - 响应式更新图形:两条对角线的端点坐标被动态改写为画布边界(如第一条线终点
(e.width, e.height)),随后调用canvas.update()将新坐标同步回 Flutter 端重绘。窗口拉大时对角线随之延伸,实现视觉上的「画布跟随窗口缩放」。 - 节流参数:
resize_interval=10与默认值一致,实际运行时可尝试调大(如 100/200)观察回调频率变化,或设为0观察无节流时的即时触发。
该示例在 pyproject.toml 中被登记为官方 Gallery 示例(title = "Canvas resize"、features = ["on_resize event", "responsive line drawing"]),可作为新建应用时的最小模板参考。
四、事件对象继承能力:Event 基类
CanvasResizeEvent继承自泛型基类Event["Canvas"](定义于 control_event.py),因此事件处理器中除了e.width/e.height,还可以访问以下通用成员:
| 成员 | 类型 | 说明 |
|---|---|---|
e.name | str | 事件名称(此处为"resize") |
e.data | Any | 原始事件载荷(dict或str,未解析前的原始数据) |
e.control | Canvas | 派发该事件的画布控件实例,可直接访问并修改其属性 |
e.page | Page | 事件源控件所属的页面(若控件未挂载到页面会抛出RuntimeError) |
e.target | int | 派发事件控件的内部 id |
借助e.control可以写出更精简的回调——例如在处理器内直接通过e.control.shapes[...]修改图形,而不必依赖外部闭包变量canvas。类型化的EventHandler[CanvasResizeEvent]意味着 IDE 与类型检查器能正确推断e的类型,这也是 Flet 事件系统「按控件类型解析事件载荷」机制的体现——相关解析逻辑get_event_field_type同样位于 control_event.py,并在 test_events.py 中有对应的类型断言测试。
五、实战场景与使用建议
1. 响应式绘图
最常见的用途就是本节官方示例展示的「坐标跟随画布尺寸」。适用于:自适应边框、随窗口缩放的网格线、图表背景、签名板清空重绘等。核心套路固定为三步:
def on_canvas_resize(e: cv.CanvasResizeEvent): # 1. 根据 e.width / e.height 重新计算图形坐标 # 2. 修改 canvas.shapes 中对应 shape 的属性 # 3. 调用 canvas.update() 推送更新 pass2. 高频场景的节流取舍
resize_interval的单位是毫秒,默认 10ms 意味着每秒最多约 100 次回调,足以保证交互流畅性。如果回调体内包含重计算(如逐点重算贝塞尔曲线、遍历上千个 shape),建议调大该值(50–200ms);如果追求极致的即时反馈(如拖拽分隔条实时预览),可设为0,但要注意连续拖动窗口时回调可能非常密集。
3. 与布局控件配合
只有画布实际占据的空间发生变化,事件才会派发。要让画布具备「可 resize」的布局前提,通常采用:
- 外层容器
expand=True(或配合width=float("inf")); - 或为
Canvas直接设置expand=True; - 或显式固定
width/height后由父级布局(如Column、Stack)驱动尺寸变化。
从源码看,Canvas继承自LayoutControl,本身具备布局能力,且before_update()会在expand=True时自动补全无穷大尺寸,这保证了展开模式下画布能跟随父容器铺满。
4. 与其他「尺寸类事件」区分
需要注意CanvasResizeEvent与页面级事件(如Page的on_resize,对应PageResizeEvent)作用对象不同:前者反映单个画布控件的渲染尺寸,后者反映整个页面/窗口尺寸。在test_events.py中可以看到PageResizeEvent的事件类型解析同样依赖get_event_field_type机制,二者属于同一套类型化事件体系的不同实例。绘制逻辑若只关心画布本身,优先使用Canvas.on_resize,无需关心窗口级状态。
六、小结与深入学习
CanvasResizeEvent是 Flet Canvas 响应式能力的核心入口:Python 侧通过Canvas.on_resize接收,字段width/height(序列化键w/h)携带逻辑像素尺寸,resize_interval控制派发频率,底层由 Flutter 端在每次绘制时测量并节流触发。掌握了它,即可让任何绘图应用随窗口缩放实时重绘。
继续深入可参考以下仓库资源:
- 类型定义与
Canvas完整成员:sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py - 官方可运行示例:sdk/python/examples/controls/core/canvas/resize/main.py
- 底层 Flutter 实现与节流逻辑:packages/flet/lib/src/controls/canvas.dart
- 事件基类与类型解析机制:sdk/python/packages/flet/src/flet/controls/control_event.py
- 事件类型解析测试:sdk/python/packages/flet/tests/test_events.py
- Canvas 控件总览文档:website/docs/controls/canvas/index.md
- 前端
- 跨平台
- 桌面应用
- 移动开发
【免费下载链接】flet
Build realtime web, mobile and desktop apps in Python only. No frontend experience required.
相关推荐
Flet ScreenBrightnessChangeEvent 详解:监听并响应屏幕亮度变化事件
Flet ScreenBrightnessChangeEvent 详解:监听并响应屏幕亮度变化事件 导读 ScreenBrightnessChangeEvent
前端跨平台桌面应用移动开发Flet 页面尺寸变化事件 PageResizeEvent 完全指南:监听窗口与浏览器尺寸变更,构建响应式布局
Flet 页面尺寸变化事件 PageResizeEvent 完全指南:监听窗口与浏览器尺寸变更,构建响应式布局 PageResizeEvent 是 Flet 中
前端跨平台桌面应用移动开发Vuetify v-resize 指令详解:监听窗口尺寸变化并触发回调
Vuetify v resize 指令详解:监听窗口尺寸变化并触发回调 v resize 是 Vuetify 提供的一个 Vue 指令,用于在浏览器窗口(win
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考