Flet Segment 控件详解:使用 Segment 构建 SegmentedButton 分段按钮
2026/9/23 12:31:07 网站建设 项目流程

Flet Segment 控件详解:使用 Segment 构建 SegmentedButton 分段按钮

【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet

flet.Segment是 Flet 中分段按钮SegmentedButton的一个分段单元,用于把一组互斥(或可多选)的选项以"标签 + 图标"的形式并排展示。本文以 website/docs/controls/segment.md 文档页为核心,结合仓库中的 Python 源码、Dart 端渲染实现与官方示例,完整讲解Segment的每个属性、校验规则,以及它和SegmentedButton配合使用时的全部关键行为,读完即可在自己的 Flet 应用中落地实现单选/多选分段控件。

Segment 在 Flet 中的定位

Segment不是一个独立展示的控件,而是专门为 SegmentedButton 服务的"零件":SegmentedButton通过segments属性接收一个Segment列表,每个Segment代表一个可点击的分段。二者定义在同一个源码文件中:

  • Python 端:sdk/python/packages/flet/src/flet/controls/material/segmented_button.py
  • Dart(Flutter)渲染端:packages/flet/lib/src/controls/segmented_button.dart

从源码看,Segment类通过@control("Segment")装饰器注册为 Flet 控件,直接继承自Control(segmented_button.py),并不继承LayoutControl,说明它只承载数据(值、图标、标签),真正负责布局与交互的是SegmentedButton。对应的 Flutter 端,SegmentedButton在构建时会遍历每个Segment并转换成 Flutter 的ButtonSegment(见 segmented_button.dart)。

Segment 的三个核心属性

Segment的全部公开属性如下表所示:

属性类型是否必填说明
valuestr标识该分段的唯一值,供selected列表引用
iconIconData \| ControlOptional显示在分段中的图标,通常是Icon
labelstr \| ControlOptional显示在分段中的标签,通常是Text

value:分段的身份标识

value是一个字符串,用于"识别这个分段"(源码 docstring 原文:"Used to identify this segment",见 segmented_button.py)。它并不直接渲染到界面上,而是被SegmentedButton.selected列表引用:例如selected=["1", "4"]表示值为"1""4"的两个分段处于选中状态。在 Dart 端,value被直接传给ButtonSegment(value: ...)(segmented_button.dart),作为选中态匹配的键。

icon 与 label:分段的内容

  • icon:通常是Icon控件(如ft.Icon(ft.Icons.LOOKS_ONE)),显示在分段前部;
  • label:通常是Text控件或普通字符串,显示分段文字(如ft.Text("One"))。

源码 docstring 明确指出:如果iconlabel都未设置(或不可见),构造Segment时会抛出ValueError(segmented_button.py)。这一约束由__validation_rules__校验规则强制执行,详见下文"源码级校验规则"。

类型别名说明

icon的类型是IconDataOrControllabel的类型是StrOrControl,这两个类型别名定义在同包的类型模块中(见 segmented_button.py 的导入)。其中StrOrControl表示"字符串或控件",意味着label既可以传一个普通字符串(如label="One"),也可以传一个Text控件以获得更精细的样式控制。

官方示例:单选择与多选择分段按钮

仓库在 sdk/python/examples/controls/material/segmented_button/single_multiple_selection/ 目录下提供了完整的可运行示例(含 main.py 和配套的 pyproject.toml),该示例同时演示了多选与单选两种模式:

import flet as ft def main(page: ft.Page): def handle_selection_change(e: ft.Event[ft.SegmentedButton]): print(e) page.add( ft.SafeArea( content=ft.Column( controls=[ ft.SegmentedButton( on_change=handle_selection_change, selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), selected=["1", "4"], allow_empty_selection=True, allow_multiple_selection=True, segments=[ ft.Segment( value="1", label=ft.Text("One"), icon=ft.Icon(ft.Icons.LOOKS_ONE), ), ft.Segment( value="2", label=ft.Text("Two"), icon=ft.Icon(ft.Icons.LOOKS_TWO), ), ft.Segment( value="3", label=ft.Text("Three"), icon=ft.Icon(ft.Icons.LOOKS_3), ), ft.Segment( value="4", label=ft.Text("Four"), icon=ft.Icon(ft.Icons.LOOKS_4), ), ], ), ft.SegmentedButton( on_change=handle_selection_change, selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), selected=["2"], allow_multiple_selection=False, segments=[ ft.Segment( value="1", label=ft.Text("One"), icon=ft.Icon(ft.Icons.LOOKS_ONE), ), ft.Segment( value="2", label=ft.Text("Two"), icon=ft.Icon(ft.Icons.LOOKS_TWO), ), ft.Segment( value="3", label=ft.Text("Three"), icon=ft.Icon(ft.Icons.LOOKS_3), ), ft.Segment( value="4", label=ft.Text("Four"), icon=ft.Icon(ft.Icons.LOOKS_4), ), ], ), ] ) ) ) if __name__ == "__main__": ft.run(main)

示例中有两点值得注意:

  1. 多选模式:第一个按钮allow_multiple_selection=Trueallow_empty_selection=True,初始选中["1", "4"]两个分段,点击已选中的分段会取消选中,允许全部取消;
  2. 单选模式:第二个按钮allow_multiple_selection=False(默认值),初始选中["2"],同一时刻只允许一个分段被选中。

on_change回调参数是ft.Event[ft.SegmentedButton],通过e.data拿到当前选中的分段值列表。Dart 端在选中变化时执行triggerEvent("change", s)并向 Python 端回写selected属性(segmented_button.dart)。

与 Segment 协同的 SegmentedButton 关键属性

虽然segment.md文档页聚焦于Segment本身,但Segment的所有行为都由SegmentedButton的以下属性驱动,二者必须在同一文件(segmented_button.py)中配套理解:

selected 与选择模式约束

  • selected: list[str]:当前选中的Segment.value列表,默认[]。用户点击分段时由框架自动更新,也可以通过编程方式设置初始值。
  • allow_empty_selection: bool:默认False。为True时允许没有任何分段被选中(selected可以为空);为False时至少需要一个分段被选中——如果用户点击唯一选中的分段,它不会被取消,且on_change不会被触发。
  • allow_multiple_selection: bool:默认False。为True时允许多选,点击已选分段会取消选中;为False时单选,选中新分段会取消之前的选中。

这三者存在强校验关系(源码__validation_rules__明确给出,segmented_button.py):

  • selected为空时必须allow_empty_selection=True,否则抛ValueError(提示 "allow_empty_selection must be True for selected to be empty");
  • selected超过一项时必须allow_multiple_selection=True,否则抛ValueError(提示 "allow_multiple_selection must be True for selected to have more than one item");
  • segments至少包含一个可见的Segment,否则抛ValueErrorV.visible_controls(min_count=1),见 segmented_button.py)。

selected_icon 与 show_selected_icon

  • selected_icon: IconDataOrControl:用于标识"已选中"状态的图标控件,默认是一个CHECK图标(Icons.CHECK)。若show_selected_icon=True,该图标会显示在选中分段的label之前,并替换该分段自身的icon(若指定了的话)。
  • show_selected_icon: bool:默认True,控制选中图标是否显示;为Falseselected_icon完全不参与渲染。

外观与布局

  • style: ButtonStyle:自定义按钮外观(前景色、背景色、圆角、阴影、边距等)。Dart 端通过getButtonStyle解析,默认前景色取主题colorScheme.primary、背景色取colorScheme.surface,Material 3 下默认形状为StadiumBorder(胶囊形),Material 2 下为圆角 4 的圆角矩形(segmented_button.dart)。
  • direction: Axis:分段的排布方向,默认Axis.HORIZONTAL(水平),可设为Axis.VERTICAL实现纵向排列。
  • padding: PaddingValue:默认None时按钮采用内容固有尺寸;一旦指定,按钮会按该 padding 扩展以填满父容器空间。

源码级校验规则与渲染链路

Python 端:Segment 的可见性校验

Segment__validation_rules__使用V.ensure(...)定义了一条关键规则(segmented_button.py):校验通过的条件是——iconIconData,或icon是控件且visible=True;或者label是字符串,或label是控件且visible=True。只要iconlabel二者中有一个"已设置且可见",校验即通过;否则抛出 "at least icon or label must be set and visible" 的ValueError

这意味着:

  • Segment(value="1", label="One")合法(有字符串标签);
  • Segment(value="1", icon=ft.Icon(...))合法(有图标);
  • Segment(value="1")不合法,直接抛异常。

Dart 端:错误态与渲染

Flutter 侧在构建SegmentedButton前会做三重防御性校验(segmented_button.dart),任一不满足都会渲染ErrorControl错误占位:

  1. segments为空 → "SegmentedButton.segments must be contain at least one visible segment";
  2. selected为空但allow_empty_selection=False→ "SegmentedButton.selected must contain at least one value...";
  3. 单选模式下selected数量不等于 1 → "SegmentedButton.selected must contain exactly one value...";
  4. 多选模式下selected数量超过分段数 → "The length of SegmentedButton.selected must be less than or equal to the number of visible segments"。

正常的渲染路径则是:遍历每个Segment,把valueenabled(继承自Control.disabled)、tooltipiconlabel组装成 Flutter 的ButtonSegment,然后交给 Material 的SegmentedButton控件(segmented_button.dart)。其中directionexpandedInsets(对应 Python 的padding)分别映射到 Flutter 的directionexpandedInsets参数。

常见用法要点

  • 初始化默认选中:通过selected=["2"]设定初始选中项,无需等待用户交互;
  • 监听选择变化on_change回调中的e.data是选中分段value的列表(即使单选模式也是列表);
  • 分段禁用Segment继承Control.disabled属性,禁用后该分段不可点击,且tooltip不会显示(Dart 端在enabled=false时传tooltip: null,见 segmented_button.dart);
  • 纵向分段:设置direction=ft.Axis.VERTICAL即可把分段改为纵向排列;
  • 自定义选中图标selected_icon=ft.Icon(ft.Icons.CHECK_SHARP)可把默认的CHECK换成任意 Material 图标。

小结

flet.SegmentSegmentedButton的最小组成单元,它通过value提供身份、通过icon/label提供内容,并受到"二者至少其一可见"的硬性校验。要真正使用它,需要与SegmentedButtonselectedallow_empty_selectionallow_multiple_selectionselected_iconshow_selected_icondirection等属性配合,Python 端负责声明式配置与校验,Dart 端负责映射为 Flutter 原生ButtonSegment并回传选择事件。文中所有示例与行为均可对照以下仓库路径进一步验证:

  • Segment / SegmentedButton Python 源码:sdk/python/packages/flet/src/flet/controls/material/segmented_button.py
  • Flutter 渲染实现:packages/flet/lib/src/controls/segmented_button.dart
  • 官方单/多选示例:sdk/python/examples/controls/material/segmented_button/single_multiple_selection/main.py
  • SegmentedButton 文档页:website/docs/controls/segmentedbutton/index.md

【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询