跳转至

SOUI中的消息通信

SOUI作为一个基于Win32 SDK的DirectUI框架,提供了多种消息通信机制。本文将详细介绍SOUI中的各种通信方式。

消息通信类型

SOUI框架中主要有三种通信机制:

  1. 真窗口消息通信
  2. SOUI控件间通信
  3. 事件机制

真窗口消息通信

发送消息

可以使用Win32 API向宿主窗口发送消息:

// 发送自定义消息
::SendMessage(hWndHost, WM_MYMSG, wParam, lParam);

// 或使用PostMessage
::PostMessage(hWndHost, WM_MYMSG, wParam, lParam);

处理消息

在宿主窗口的消息映射表中处理消息:

// 自定义消息定义
#define WM_MYMSG (WM_USER+100)

// 消息处理函数
LRESULT OnMyMsg(UINT uMsg, WPARAM wp, LPARAM lp, BOOL& bHandled)
{
    // 处理消息
    return 0;
}

// 消息映射表(WTL风格)
BEGIN_MSG_MAP_EX(CMainDlg)
    MESSAGE_HANDLER(WM_MYMSG, OnMyMsg)
    MSG_WM_CREATE(OnCreate)
    MSG_WM_DESTROY(OnDestory)
    CHAIN_MSG_MAP(SHostWnd)
    REFLECT_NOTIFICATIONS_EX()
END_MSG_MAP()

SOUI控件间通信

发送消息

使用SSendMessage向SOUI窗口发送消息:

// 发送消息到SOUI窗口
pWindow->SSendMessage(uMsg, wParam, lParam);

注意:SOUI不支持PostMessage机制。

处理消息

在SOUI窗口的消息映射表中处理消息:

class SMyWindow : public SWindow
{
protected:
    void OnPaint(IRenderTarget *pRT);
    void OnLButtonDown(UINT nFlags, CPoint pt);
    void OnMouseMove(UINT nFlags, CPoint pt);

    SOUI_MSG_MAP_BEGIN()
        MSG_WM_PAINT_EX(OnPaint)
        MSG_WM_LBUTTONDOWN(OnLButtonDown)
        MSG_WM_MOUSEMOVE(OnMouseMove)
    SOUI_MSG_MAP_END()
};

常用消息映射宏

SOUI宏 Win32消息 说明
MSG_WM_PAINT_EX WM_PAINT 绘制消息
MSG_WM_ERASEBKGND_EX WM_ERASEBKGND 擦除背景
MSG_WM_SETFONT_EX WM_SETFONT 设置字体

事件机制

事件定义

// 自定义事件参数
class EventMyCustom : public TplEventArgs<EventMyCustom>
{
    SOUI_CLASS_NAME(EventMyCustom, L"on_my_custom")
public:
    EventMyCustom(SObject *pSender) : TplEventArgs<EventMyCustom>(pSender) {}

    int eventData;  // 事件数据
};

触发事件

void SMyWindow::TriggerCustomEvent()
{
    EventMyCustom evt(this);
    evt.eventData = 100;
    FireEvent(evt);
}

处理事件

方式1:事件映射表

// 事件处理函数
BOOL OnMyCustomEvent(EventMyCustom *pEvt)
{
    int data = pEvt->eventData;
    return TRUE;
}

// 事件映射
EVENT_MAP_BEGIN()
    EVENT_HANDLER(EventMyCustom::EventID, OnMyCustomEvent)
EVENT_MAP_END()

方式2:事件订阅

// 订阅特定窗口的事件
pWindow->subscribeEvent(EventMyCustom::EventID, 
    [](EventArgs *e)->bool{
        EventMyCustom *evt = (EventMyCustom*)e;
        // 处理事件
        return true;
    });

最佳实践

1. 选择合适的通信方式

  • 与宿主窗口通信:使用真窗口消息
  • SOUI控件间通信:使用SSendMessage
  • 控件状态变化通知:使用事件机制

2. 消息处理注意事项

  1. 消息映射
  2. 使用正确的映射宏
  3. 注意消息处理顺序

  4. 参数传递

  5. 合理使用wParam/lParam
  6. 避免传递野指针

  7. 返回值处理

  8. 正确设置bHandled
  9. 返回适当的值

3. 事件处理建议

  1. 事件定义
  2. 合理设计事件参数
  3. 使用有意义的事件名

  4. 事件订阅

  5. 及时取消不需要的订阅
  6. 避免循环引用

  7. 性能优化

  8. 减少不必要的事件触发
  9. 优化事件处理逻辑

调试技巧

  1. 消息跟踪
  2. 使用SPyView跟踪消息
  3. 打印关键消息信息

  4. 事件调试

  5. 设置事件断点
  6. 跟踪事件传播路径

  7. 常见问题排查

  8. 消息没有被处理
  9. 事件没有触发
  10. 参数传递错误