name: makepad-event-action description: | 关键:用于Makepad事件和动作处理。触发于: makepad事件、makepad动作、Event枚举、ActionTrait、handle_event、 MouseDown、KeyDown、TouchUpdate、Hit、FingerDown、post_action、 makepad事件、makepad动作、事件处理
Makepad事件/动作技能
版本: makepad-widgets(开发分支) | 最后更新: 2026-01-19
您是一位Makepad事件和动作处理专家。通过以下方式帮助用户:
- 处理事件:鼠标、键盘、触摸、生命周期事件
- 创建动作:小部件到父级的通信
- 事件流:理解事件传播
文档
参考本地文件获取详细文档:
./references/event-system.md- 事件枚举和处理./references/action-system.md- 动作特征和模式
重要:文档完整性检查
回答问题前,Claude必须:
- 阅读上述列出的相关参考文件
- 如果文件读取失败或文件为空:
- 通知用户:“本地文档不完整,建议运行
/sync-crate-skills makepad --force更新文档” - 仍基于SKILL.md模式+内置知识回答
- 通知用户:“本地文档不完整,建议运行
- 如果参考文件存在,将其内容融入答案中
事件枚举(关键变体)
pub enum Event {
// 生命周期
Startup,
Shutdown,
Foreground,
Background,
Resume,
Pause,
// 绘图
Draw(DrawEvent),
LiveEdit,
// 窗口
WindowGotFocus(WindowId),
WindowLostFocus(WindowId),
WindowGeomChange(WindowGeomChangeEvent),
WindowClosed(WindowClosedEvent),
// 鼠标
MouseDown(MouseDownEvent),
MouseMove(MouseMoveEvent),
MouseUp(MouseUpEvent),
Scroll(ScrollEvent),
// 触摸
TouchUpdate(TouchUpdateEvent),
// 键盘
KeyDown(KeyEvent),
KeyUp(KeyEvent),
TextInput(TextInputEvent),
TextCopy(TextClipboardEvent),
// 定时器
Timer(TimerEvent),
NextFrame(NextFrameEvent),
// 网络
HttpResponse(HttpResponse),
// 小部件动作
Actions(ActionsBuf),
}
在小部件中处理事件
impl Widget for MyWidget {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
// 检查事件是否击中此小部件的区域
match event.hits(cx, self.area()) {
Hit::FingerDown(fe) => {
// 鼠标/触摸按下此小部件
cx.action(MyWidgetAction::Pressed);
}
Hit::FingerUp(fe) => {
if fe.is_over {
// 释放时仍在小部件上 = 点击
cx.action(MyWidgetAction::Clicked);
}
}
Hit::FingerHoverIn(_) => {
self.animator_play(cx, id!(hover.on));
}
Hit::FingerHoverOut(_) => {
self.animator_play(cx, id!(hover.off));
}
Hit::KeyDown(ke) => {
if ke.key_code == KeyCode::Return {
cx.action(MyWidgetAction::Submitted);
}
}
_ => {}
}
}
}
Hit枚举
pub enum Hit {
// 手指/鼠标
FingerDown(FingerDownEvent),
FingerUp(FingerUpEvent),
FingerMove(FingerMoveEvent),
FingerHoverIn(FingerHoverEvent),
FingerHoverOver(FingerHoverEvent),
FingerHoverOut(FingerHoverEvent),
FingerLongPress(FingerLongPressEvent),
// 键盘
KeyDown(KeyEvent),
KeyUp(KeyEvent),
KeyFocus,
KeyFocusLost,
TextInput(TextInputEvent),
TextCopy,
// 无
Nothing,
}
动作系统
定义动作
#[derive(Clone, Debug, DefaultNone)]
pub enum ButtonAction {
None,
Clicked,
Pressed,
Released,
}
// DefaultNone派生默认返回None变体
发射动作
// 从主线程(在handle_event中)
cx.action(ButtonAction::Clicked);
// 从任何线程(线程安全)
Cx::post_action(MyAction::DataLoaded(data));
处理动作
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
// 处理子小部件动作
let actions = cx.capture_actions(|cx| {
self.button.handle_event(cx, event, scope);
});
// 检查特定动作
if self.button(id!(my_button)).clicked(&actions) {
// 按钮被点击
}
// 或迭代动作
for action in actions.iter() {
if let Some(ButtonAction::Clicked) = action.downcast_ref() {
// 处理点击
}
}
}
小部件动作助手
// 常见小部件动作检查
impl ButtonRef {
fn clicked(&self, actions: &ActionsBuf) -> bool;
fn pressed(&self, actions: &ActionsBuf) -> bool;
fn released(&self, actions: &ActionsBuf) -> bool;
}
impl TextInputRef {
fn changed(&self, actions: &ActionsBuf) -> Option<String>;
fn returned(&self, actions: &ActionsBuf) -> Option<String>;
}
事件流
- 事件到达 从平台层
- 根小部件 首先接收事件
- 向下传播 到子级通过
handle_event - 小部件发射动作 通过
cx.action() - 父级捕获动作 通过
cx.capture_actions() - 应用处理 剩余动作
定时器和下一帧
// 启动定时器
let timer = cx.start_timer(1.0); // 1秒
// 在handle_event中
if let Event::Timer(te) = event {
if te.timer_id == self.timer {
// 定时器触发
}
}
// 请求下一帧回调
let next_frame = cx.new_next_frame();
// 在handle_event中
if let Event::NextFrame(ne) = event {
if ne.frame_id == self.next_frame {
// 下一帧到达
}
}
回答问题时
- 使用
event.hits(cx, area)检查事件是否目标小部件 - 动作从子级向上流动到父级(与事件向下流动相反)
- 使用
cx.capture_actions()拦截子动作 Cx::post_action()是线程安全的用于异步操作DefaultNone派生宏自动为枚举实现默认值