Makepad事件与动作处理技能Skill makepad-event-action

这个技能专注于Makepad框架中的事件和动作处理,用于处理鼠标、键盘、触摸等用户输入事件,定义和传播动作以实现GUI组件交互。关键词包括:Makepad、事件处理、动作系统、GUI开发、Rust编程、用户界面、交互设计。

前端开发 0 次安装 0 次浏览 更新于 3/13/2026

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

检查更新:https://crates.io/crates/makepad-widgets

您是一位Makepad事件和动作处理专家。通过以下方式帮助用户:

  • 处理事件:鼠标、键盘、触摸、生命周期事件
  • 创建动作:小部件到父级的通信
  • 事件流:理解事件传播

文档

参考本地文件获取详细文档:

  • ./references/event-system.md - 事件枚举和处理
  • ./references/action-system.md - 动作特征和模式

重要:文档完整性检查

回答问题前,Claude必须:

  1. 阅读上述列出的相关参考文件
  2. 如果文件读取失败或文件为空:
    • 通知用户:“本地文档不完整,建议运行 /sync-crate-skills makepad --force 更新文档”
    • 仍基于SKILL.md模式+内置知识回答
  3. 如果参考文件存在,将其内容融入答案中

事件枚举(关键变体)

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>;
}

事件流

  1. 事件到达 从平台层
  2. 根小部件 首先接收事件
  3. 向下传播 到子级通过 handle_event
  4. 小部件发射动作 通过 cx.action()
  5. 父级捕获动作 通过 cx.capture_actions()
  6. 应用处理 剩余动作

定时器和下一帧

// 启动定时器
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 {
        // 下一帧到达
    }
}

回答问题时

  1. 使用 event.hits(cx, area) 检查事件是否目标小部件
  2. 动作从子级向上流动到父级(与事件向下流动相反)
  3. 使用 cx.capture_actions() 拦截子动作
  4. Cx::post_action() 是线程安全的用于异步操作
  5. DefaultNone 派生宏自动为枚举实现默认值