Gradio 事件监听器完全指南:组件事件签名、支持矩阵与 Blocks 实战用法
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
本文以官方仓库 .agents/skills/gradio/references/event-listeners.md 为核心脉络,结合 gradio/events.py、gradio/components 下的组件实现,系统讲解 Gradio 中"每个组件支持哪些事件、事件监听器方法有哪些参数、如何把它们接入函数与界面"的完整知识。读完你将对
change / click / input / select / submit等事件的触发语义、通用签名中二十多个参数的默认值与真实作用,以及gr.on()、链式事件、事件数据对象(EventData)等进阶用法有可落地、可验证的理解,能直接在 Blocks 应用中编写出正确、健壮的交互逻辑。
一、事件监听器在 Gradio 中扮演什么角色
在 Gradio 的Blocks编程模型中,一个界面应用(demo)本质上是一张由组件构成的"图",而**事件监听器(Event Listener)**就是驱动这张图运转的边:用户在前端操作某个组件(点击、输入、选择……),对应的监听器被触发,把若干输入组件的值交给一个 Python 函数处理,再把函数的返回值写回若干输出组件。
用户操作组件 --触发--> 事件监听器(event_name) --> 后端 fn(预处理后的输入) | 用户界面显示组件 <--事件完成-- Dependency 对象 <-- fn 返回(后处理)结果这套机制的核心源码位于 gradio/events.py,其中包括:
EventListener:对事件(如change、click)的描述与绑定工厂;Events类:集中定义所有可用事件,并为每个事件提供说明文档字符串;Dependency:一次成功绑定事件后返回的"依赖"对象,支持.then()/.success()/.failure()链式续接;gr.on()与gr.api():非组件维度的通用事件注册入口;EventData及其子类(SelectData、LikeData等):把事件发生时的上下文信息注入回调函数。
而"每个组件能响应哪些事件",则由各组件的EVENTS类属性显式声明。例如 Button 组件 声明EVENTS = [Events.change, Events.click],Textbox 组件 声明了change / input / select / submit / focus / blur / stop / copy共 8 个事件,Chatbot 组件 则声明了change / select / like / retry / undo / example_select / option_select / clear / copy / edit。组件类上对应的EVENTS列表即"该组件支持事件的权威清单",见下文第四节。
二、事件监听器统一签名与参数详解
无论你调用button.click(...)、textbox.submit(...)还是slider.change(...),它们在 Python 侧都收敛到同一个底层函数签名(源码见 gradio/events.py 中EventListener._setup()生成的event_trigger),各参数含义完全一致:
component.event_name( fn: Callable | None | Literal["decorator"] = "decorator", inputs: Component | Sequence[Component] | set[Component] | None = None, outputs: Component | Sequence[Component] | set[Component] | None = None, api_name: str | None = None, api_description: str | None | Literal[False] = None, scroll_to_output: bool = False, show_progress: Literal["full", "minimal", "hidden"] = "full", show_progress_on: Component | Sequence[Component] | None = None, queue: bool = True, batch: bool = False, max_batch_size: int = 4, preprocess: bool = True, postprocess: bool = True, cancels: dict[str, Any] | list[dict[str, Any]] | None = None, trigger_mode: Literal["once", "multiple", "always_last"] | None = None, js: str | Literal[True] | None = None, concurrency_limit: int | None | Literal["default"] = "default", concurrency_id: str | None = None, api_visibility: Literal["public", "private", "undocumented"] = "public", time_limit: int | None = None, stream_every: float = 0.5, key: int | str | tuple[int | str, ...] | None = None, validator: Callable | None = None, ) -> Dependency与函数式编程直观对应:inputs指定回调函数的入参来源,outputs指定回调返回值的去向,fn即被调用的处理函数。整体流程为:事件触发 → 对输入组件做preprocess→ 执行fn→ 对结果做postprocess→ 更新输出组件。参数默认值与说明可对照 gradio/events.py 的官方 docstring,下面逐项展开。
1. 核心三参数:fn、inputs、outputs
| 参数 | 默认值 | 说明 |
|---|---|---|
fn | "decorator"(见下) | 事件触发时调用的函数,通常是机器学习模型的预测函数。fn的每个参数对应一个输入组件,返回值可以是单个值或元组,元组内元素依次对应各输出组件。 |
inputs | None | 用作函数输入的组件,接受单个Component或组件序列/集合。若函数无输入,传空列表。 |
outputs | None | 接收函数返回值的组件,规则同inputs。若函数无输出,传空列表。 |
函数与组件的对应关系是 Gradio 最核心的约定:第i个输入参数 ← 第i个inputs组件;返回元组的第j个值 → 第j个outputs组件。若outputs组件数大于返回值数,多余的输出组件会被填充为None。
fn默认值"decorator"意味着事件绑定支持装饰器语法:当事件方法自身没有传入函数(fn="decorator")时,调用返回的包装对象可直接作为@装饰器套在函数上,例如:
import gradio as gr with gr.Blocks() as demo: name = gr.Textbox(label="姓名") greeting = gr.Textbox(label="问候") @name.submit def greet(name: str) -> str: return f"你好, {name}!" demo.launch()从 gradio/events.py 的event_trigger实现看,装饰器模式会把函数真正注册进Blocks上下文,同时返回一个保留原函数签名的wrapper,因此既可以直接写component.event(fn, inputs, outputs),也可以把事件方法当作装饰器使用。
2. 接口层参数:api_name、api_description、api_visibility
这三个参数控制该事件对应后端 API 端点的对外形态:
api_name:定义端点出现在 API 文档中的名字。传字符串则按给定名暴露(客户端调用时前面加/);默认None时使用fn的函数名作为端点名。api_description:端点描述。传字符串则使用该描述;传None(默认)时使用函数 docstring;传False时 API 文档不展示任何描述。api_visibility:端点的可见性与可调用性,三选一:"public"(默认):显示在 API 文档中,Gradio 客户端库可调用;"private":从 API 文档隐藏,且 Gradio 客户端库不可调用;"undocumented":文档中隐藏,但客户端与gr.load仍可调用。- 注意:若
fn为None(纯 JS 事件等场景),api_visibility会被自动置为"private"。
3. 视觉反馈参数:scroll_to_output、show_progress、show_progress_on
| 参数 | 默认值 | 作用 |
|---|---|---|
scroll_to_output | False | 为True时,事件完成后页面自动滚动到输出组件位置。 |
show_progress | "full" | 事件运行期间的进度动画策略。"full"显示覆盖输出区域的 spinner 及右上角的运行时状态;"minimal"只显示右上角运行时状态;"hidden"完全不显示进度动画。 |
show_progress_on | None | 指定在哪些组件上展示进度动画;为None时展示在所有输出组件上。 |
顺带一提:源码对布尔值做了向后兼容处理,若历史代码传入show_progress=True/False,会被自动映射为"full"/"hidden"(见event_trigger中的isinstance(show_progress, bool)分支)。
4. 队列与批处理参数:queue、batch、max_batch_size
queue:True表示在队列开启时把请求放入队列;False表示即便应用开启队列也不排队;传None则沿用应用的队列设置。需要排队才能使用生成器流式输出、进度条等能力。batch:为True时,fn必须以"批"方式处理输入——每个参数接收一个等长列表(长度不超过max_batch_size),并且必须返回元组形式的列表(哪怕只有一个输出组件),每个列表对应一个输出组件。max_batch_size:仅当batch=True且经由队列调用时有效,表示一次最多合并多少个输入。
5. 数据预处理参数:preprocess、postprocess
preprocess=True(默认)会在执行fn前把组件数据转换为 Python 对象(例如Image转为 numpy 数组);设为False则不做转换,直接以原始载荷(如 base64 字符串)传入fn。postprocess=True(默认)会把fn的返回值转成浏览器可渲染的组件格式;设为False则原样透传。
6. 事件编排参数:cancels、trigger_mode
cancels:当本事件被触发时,需要一并取消的其它事件列表。例如保存某次button.click的返回对象为click_event,再设cancels=[click_event],则新事件触发时会取消该点击事件——尚未运行的函数以及正在迭代的生成器会被取消,正在运行的函数则允许运行到结束。计时器类事件(如Timer)也会被特殊处理。取消逻辑实现在set_cancel_events()(gradio/events.py),会把普通取消与Timer(active=False)取消分开注册。trigger_mode:控制事件触发频率与并发提交行为:"once":事件处理期间不允许再次提交(除.change()外大多数事件的默认值);"multiple":处理期间允许无限次提交;"always_last":处理完成后若期间有新提交,仅执行最后一次(.change()与.key_up()的默认值)。
7. 前端 JS 参数:js
js接受一段前端 JS 代码字符串,在运行fn之前于浏览器中执行。JS 函数的入参是各输入组件的值,返回值应当是对应输出组件的值列表。纯字符串 JS 事件可以不依赖后端函数运行:从event_trigger的源码逻辑看,当js为字符串且不采用装饰器时,会以fn=None立即注册一个纯前端事件。若同时传入js=True(类型标注允许),可用于辅助仅含 JS 的监听器场景。
8. 并发控制参数:concurrency_limit、concurrency_id
concurrency_limit:该事件最多可同时运行的数量上限。None表示不限并发;"default"(默认)表示使用默认并发上限——由Blocks.queue()的default_concurrency_limit决定(其自身默认为 1)。concurrency_id:并发组的标识。拥有相同concurrency_id的事件共享并发额度,受组内最低的concurrency_limit约束。
9. 流式与时间参数:time_limit、stream_every
time_limit:仅对.stream()事件有效,限制函数的运行时间。stream_every:仅对.stream()事件有效,控制流式数据块回传后端的间隔延迟(秒),默认0.5秒。
10. 渲染与校验参数:key、validator
key:给该事件监听器一个唯一标识,用于@gr.render()场景。设置后,当key一致时,事件在多次 re-render 之间被视为同一个事件,从而跨渲染保留状态。validator:在主函数执行前运行的校验函数。校验函数以queue=False方式先行执行,只有校验通过才调用主函数;它接收与主函数相同的输入,并应对每个输入值返回gr.validate()的结果。
返回值:Dependency
所有事件监听方法都返回一个Dependency对象(它是dict的子类,保存了本次绑定的配置数据与fn),其最常用的价值在于链式续接事件(详见第六节):
dep.then(...):直接前驱事件完成后触发,无论成功与否;dep.success(...):直接前驱事件成功完成后触发;dep.failure(...):直接前驱事件失败后触发。
三者的真实语义可从 gradio/events.py 中Dependency.__init__的实现读出:它们分别以trigger_only_on_success=False/True和trigger_only_on_failure=True的组合构造后续监听器。官方示例可运行 demo/blocks_chained_events/run.py 查看真实效果。
三、事件触发语义速查
在逐个组件列出支持事件前,先理解高频事件的通用语义(均摘录自 gradio/events.py 中Events类的 docstring):
| 事件 | 触发时机 | 备注 |
|---|---|---|
change | 组件值发生变化——无论是用户输入(如在文本框中打字)还是函数更新输出(组件收到某事件返回的新值) | 若只想监听用户输入请用input;默认trigger_mode="always_last" |
input | 用户改变了组件值 | 与change的关键区别:不响应后端函数更新 |
click/double_click | 用户单击 / 双击组件 | |
select | 用户选中或取消选中组件内的某项 | 携带SelectData事件数据,组件会被标记为可选择(源码通过setattr(block, "_selectable", True)生效) |
submit | 组件聚焦时用户按下回车键 | |
focus/blur | 组件获得 / 失去焦点 | |
upload | 用户向组件上传文件 | |
clear | 用户通过组件的清除按钮清空组件 | |
play/pause/stop/end | 媒体组件播放 / 暂停 / 用户点击停止按钮或图标 / 播放至结尾 | |
start_recording/pause_recording/stop_recording | 用户开始 / 暂停 / 停止录音或录屏 | |
stream | 用户向组件(如麦克风)持续输入流式数据 | 走connection="stream"通道,携带stream_every与time_limit专属参数 |
edit | 用户用组件内置编辑器编辑内容 | 源码回调会把组件editable置为"user" |
like | 用户在组件内点赞 / 点踩 | 仅 Chatbot 等携带;通过setattr(block, "likeable", True)生效 |
retry/undo | 用户点击消息上的重试 / 撤销按钮 | 仅 Chatbot;回调会把组件标记为_retryable/_undoable |
example_select/option_select | 用户点击组件内示例 / 选项 | 携带SelectData |
delete/download/copy | 用户删除条目 / 下载文件 / 复制内容 | 分别携带DeletedFileData/DownloadData/CopyData |
key_up | 用户按键抬起 | 携带KeyUpData,默认trigger_mode="always_last" |
tick | 按组件定义的固定间隔周期触发 | 主要用于Timer,默认不显示进度 |
expand/collapse | 组件被展开 / 收起 | |
apply | 用户通过集成 UI 动作应用更改 | |
load | 组件在浏览器中首次加载完成 | 页面级.load()定义于Blocks |
四、组件支持事件全矩阵
EVENTS类属性即各组件"可用事件"的权威清单(源码位置见各组件文件,如 gradio/components/button.py)。下表完整列出参考文档登记的全部组件事件(事件顺序与原文一致):
| 组件 | 支持的事件 |
|---|---|
| AnnotatedImage | change、select |
| Audio | stream、change、clear、play、pause、stop、start_recording、pause_recording、stop_recording、upload、input |
| BarPlot | change、select、double_click |
| BrowserState | change |
| Button | change、click |
| Chatbot | change、select、like、retry、undo、example_select、option_select、clear、copy、edit |
| Checkbox | change、input、select |
| CheckboxGroup | change、input、select |
| ClearButton | change、click |
| Code | change、input、focus、blur |
| ColorPicker | change、input、release、submit、focus、blur |
| Dataframe | change、input、select、edit |
| Dataset | change、click、select |
| DateTime | change、submit |
| DeepLinkButton | change、click |
| Dialogue | change、input、submit |
| DownloadButton | change、click |
| Dropdown | change、input、select、focus、blur、key_up |
| DuplicateButton | change、click |
| File | change、select、clear、upload、delete、download |
| FileExplorer | change、input、select |
| Gallery | select、upload、change、delete、preview_close、preview_open |
| HTML | change、input、click、double_click、submit、stop、edit、clear、play、pause、end、start_recording、pause_recording、stop_recording、focus、blur、upload、release、select、stream、like、example_select、option_select、load、key_up、apply、delete、tick、undo、retry、expand、collapse、download、copy |
| HighlightedText | change、select |
| Image | clear、change、stream、select、upload、input |
| ImageEditor | clear、change、input、select、upload、apply |
| ImageSlider | clear、change、stream、select、upload、input |
| JSON | change |
| Label | change、select |
| LinePlot | change、select、double_click |
| LoginButton | change、click |
| Markdown | change、copy |
| Model3D | change、upload、edit、clear |
| MultimodalTextbox | change、input、select、submit、focus、blur、stop |
| Navbar | change |
| Number | change、input、submit、focus、blur |
| ParamViewer | change、upload |
| Plot | change |
| Radio | select、change、input |
| ScatterPlot | change、select、double_click |
| SimpleImage | clear、change、upload |
| Slider | change、input、release |
| State | change |
| Textbox | change、input、select、submit、focus、blur、stop、copy |
| Timer | change、tick |
| UploadButton | change、click、upload |
| Video | change、clear、start_recording、stop_recording、stop、play、pause、end、upload、input |
| WorkflowCanvas | change |
几点值得留意的细节:
- HTML 组件几乎是"全事件容器",几乎所有浏览器事件都被挂载,适合用原生 HTML 元素快速搭建自定义交互原型。
- Audio / Video 是事件大户,覆盖了媒体播放与录制全生命周期。
- Plot 系组件(BarPlot / LinePlot / ScatterPlot)支持
select与double_click,可用于图表交互。 - 官方 IDE 类型提示中,上述事件方法由 gradio/component_meta.py 根据
EVENTS声明自动生成各组件类的.pyi存根,模板会为事件注入与第二节完全一致的通用参数签名(部分事件还追加专属参数,如.stream()的stream_every)。这意味着写代码时 IDE 会精确提示某个组件可用的事件与参数,你也可以直接查看自动生成的接口签名确认。
五、事件专属数据:EventData 与各类子类
不少事件在触发时能提供"事件上下文"。在回调函数中,把参数类型标注为gr.EventData(或其子类),Gradio 就会自动把相应事件数据对象注入该参数(定义见 gradio/events.py):
import gradio as gr with gr.Blocks() as demo: table = gr.Dataframe([[1, 2, 3], [4, 5, 6]]) gallery = gr.Gallery([("cat.jpg", "Cat"), ("dog.jpg", "Dog")]) textbox = gr.Textbox("Hello World!") statement = gr.Textbox() def on_select(value, evt: gr.EventData): return f"你在 {evt.target} 上选中了内容,其值为 {value}。" table.select(on_select, table, statement) gallery.select(on_select, gallery, statement) textbox.select(on_select, textbox, statement) demo.launch()EventData基类通过__getattr__把事件负载暴露为属性,最核心的是target——触发事件的组件对象,可用于多个组件共享同一监听逻辑时区分来源。
各子类携带的额外信息如下:
| 事件数据类 | 适用于 | 主要属性 |
|---|---|---|
SelectData | .select() | index(选中项下标,二维组件或范围选择时为元组)、value(选中项的值)、row_value/col_value(Dataframe 中整行 / 整列值)、selected(选中为True,取消选中为False) |
KeyUpData | .key_up() | key(按下的键)、input_value(按键后输入框内显示值;可能尚未同步到组件value,例如 Dropdown 需按回车才提交) |
LikeData | Chatbot.like() | index、value(被点赞 / 点踩的消息内容与下标)、liked(True赞 /False踩 / 字符串表示其它反馈) |
RetryData | Chatbot.retry() | index(应重试的用户消息下标)、value |
UndoData | Chatbot.undo() | index、value(应撤销的消息下标与内容) |
EditData | Chatbot.edit() | index、previous_value(编辑前内容)、value(编辑后新内容) |
DeletedFileData | .delete() | file(被删除的文件,FileData对象,如file.path) |
DownloadData | .download() | file(被下载的文件,FileData对象) |
CopyData | .copy() | value(被复制的内容) |
实际示例可参考仓库 Demo:demo/dropdown_key_up/run.py(KeyUpData)、demo/gallery_selections(SelectData与选中逻辑)、demo/file_component_events(DeletedFileData/DownloadData)。
六、事件监听的多形态用法
1. 标准绑定式(最常用)
import gradio as gr def greet(name): return f"你好,{name}!" with gr.Blocks() as demo: name = gr.Textbox(label="姓名") output = gr.Textbox(label="结果") greet_btn = gr.Button("打招呼") greet_btn.click(greet, inputs=name, outputs=output) demo.launch()注意一个经常被误解的点:事件方法的第一个位置参数是fn,而button本身是否是fn的输入由inputs决定——Button 作为输入组件(其值为按钮文案)属于少见用法。
2. 多事件共享一个函数:gr.on()
当多个事件需要触发同一个函数时,用 gradio/events.py 中定义的gr.on()合并注册,且只为整组触发器生成一个API 端点:
import gradio as gr with gr.Blocks() as demo: with gr.Row(): input_text = gr.Textbox() button = gr.Button("Submit") output = gr.Textbox() @gr.on(triggers=[button.click, input_text.submit]) def process(x): return x.upper() # 等价写法: # gr.on(triggers=[button.click, input_text.submit], # fn=lambda x: x.upper(), inputs=input_text, outputs=output) demo.launch()triggers若为None,则监听"应用加载 + 任意输入组件变化",这在输入组件动态变化时非常有用。
3. 装饰器式事件(前文已述)
事件方法自身可作为装饰器(fn默认"decorator"):
with gr.Blocks() as demo: slider = gr.Slider(0, 100) num = gr.Number() @slider.release def show_value(v): return v4. 链式事件:.then()/.success()/.failure()
把一个事件的结果继续"喂"给后续事件,形成调用链,是构建多步骤应用(如对话机器人多轮处理)的核心手法。行为验证来自仓库 Demo demo/blocks_chained_events/run.py:
import gradio as gr def success(): return "第一个事件成功" def then_event(x): return f"{x},随后事件也被触发" with gr.Blocks() as demo: result = gr.Textbox() result_2 = gr.Textbox() run_btn = gr.Button("运行") event = run_btn.click(success, None, result) # 先运行 event.then(then_event, result, result_2) # 无论成败都继续 event.success(lambda: "成功路径", None, result) # 仅成功时 event.failure(lambda: "失败路径", None, result) # 仅失败时 demo.launch().then()/.success()/.failure()链本身也支持继续挂链,形成多级流水线;.then()链也常与生成器、流式输出配合实现"先生成再处理"的 AI 应用编排。
5. 纯 JS 前端事件与cancels取消
当fn=None、仅提供js字符串时,事件可完全在前端运行,无需后端往返;而cancels参数则在 AI 应用中用来实现"停止生成"按钮——把生成事件对象传入停止按钮事件的cancels=[gen_event],用户点击停止即可取消仍在迭代的生成器。这正是Button的variant="stop"样式与stop事件的典型搭配场景。
6. 组件级加载与页面加载事件
- 组件
.load():绑定组件在浏览器中首次渲染完成的回调; - 页面级
demo.load(fn):Blocks.load定义在 gradio/blocks.py 中,用于应用加载后执行初始化逻辑(预填下拉、读取会话状态等)。
七、底层实现机制(理解即可,勿需记忆)
为了让读者更自信地使用上述 API,这里梳理一遍事件从声明到触发的完整源码链路:
事件定义:所有事件集中定义在 gradio/events.py 的
Events类(change、input、click……每个都是一次EventListener(...)实例化,附有 docstring 与默认参数,部分事件带callback副作用与event_specific_args)。文件末尾的all_events汇总全部事件实例供框架遍历。组件声明:每个组件在类体中写
EVENTS = [...]说明它支持的事件(如 gradio/components/button.py#L25、gradio/components/textbox.py#L59)。Component基类(gradio/components/base.py)提供has_event()判断某事件是否被组件支持,并为动态计算值、Timer的tick等内置绑定机制提供基础。接口注入:gradio/component_meta.py 中的
INTERFACE_TEMPLATE以 Jinja 模板为每个组件类的EVENTS生成.click()、.change()等方法的类型签名,因此 IDE 能精确提示"哪个组件有哪些事件、参数长什么样"。触发与调度:组件事件方法内部调用
EventListener._setup()构造的event_trigger,最终路由到Blocks.set_event_trigger()(gradio/blocks.py)把触发器注册为Dependency;queue/batch/concurrency等参数与队列子系统、API 层衔接,Dependency对象即最终返回给用户的句柄。事件数据注入:需要事件上下文时,前端负载随请求一起进入后端,Gradio 依据回调函数参数的类型标注把
EventData及其子类实例注入对应形参。
八、小结
- 事件能力由组件决定:查组件的
EVENTS声明(gradio/components 目录)或直接依赖 IDE 自动补全即可知道可用事件。 - 签名完全统一:
fn、inputs、outputs三大件 + 20 余个可选参数覆盖了 API 暴露、进度展示、队列批处理、前端 JS、并发取消、流式与校验等全部控制维度,一次掌握即可全组件通用。 - 三种绑定形态:方法式
component.event(fn, ...)、装饰器式@component.event、聚合式gr.on(triggers=[...])。 - 善用返回值:绑定返回的
Dependency支持.then()/.success()/.failure()链式编排,再叠加EventData系列对象即可实现从"简单点击"到"多轮对话、批量生成、流式取消"的丰富交互。
建议读者动手运行仓库中的 demo/blocks_chained_events/run.py、demo/gallery_selections 与 demo/calculator 等示例,在真实界面中验证change与input的差异、SelectData的取值以及链式事件的成功 / 失败分支——这是比阅读本文更快的内化方式。
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考