跳转至

SOUI 与 WTL 的关系及集成

SOUI虽然不依赖于WTL,但在设计上借鉴了很多WTL的优秀特性,特别是在消息处理和事件机制方面。本文将详细介绍SOUI与WTL的关系,帮助开发者更好地理解和使用SOUI框架。

WTL基础知识的重要性

如果你想使用SOUI,建议先了解一些WTL的基础知识。你不需要成为WTL专家,但了解其基本概念会对使用SOUI有很大帮助。

如果你想使用 SOUI 最好有点 WTL 基础,一点点就行了。

消息处理机制

SOUI在两个层次上模仿了WTL的消息处理形式:

1. SWindow及其派生类中的消息处理

在SOUI中,控件的消息处理使用了与WTL非常相似的消息映射宏:

SOUI_MSG_MAP_BEGIN()
    MSG_WM_PAINT_EX(OnPaint)
    MSG_WM_DESTROY(OnDestroy)
    MSG_WM_LBUTTONDOWN(OnLButtonDown)
    MSG_WM_MOUSEMOVE(OnMouseMove)
    MSG_WM_MOUSELEAVE(OnMouseLeave)
    MSG_WM_KEYDOWN(OnKeyDown)
SOUI_MSG_MAP_END()

主要区别在于: - SOUI使用SOUI_MSG_MAP_BEGIN/END()而不是WTL的宏 - WM_PAINT消息处理使用MSG_WM_PAINT_EX,因为SOUI使用IRenderTarget而不是HDC

2. CSimpleWnd派生类中的消息处理

在真窗口消息处理中(如SHostWnd, SHostDialog),SOUI直接使用WTL的消息映射宏:

//HOST 消息及响应函数映射表
BEGIN_MSG_MAP_EX(CMainDlg)
    MSG_WM_CREATE(OnCreate)
    MSG_WM_INITDIALOG(OnInitDialog)
    MSG_WM_DESTROY(OnDestory)
    MSG_WM_CLOSE(OnClose)
    MSG_WM_SIZE(OnSize)
    MSG_WM_COMMAND(OnCommand)
    MSG_WM_SHOWWINDOW(OnShowWindow)
    CHAIN_MSG_MAP(SHostWnd)
    REFLECT_NOTIFICATIONS_EX()
END_MSG_MAP()

消息传递注意事项

由于 SWindow 的消息来自 SHostWnd 的消息分发,如果在 SHostWnd 或者 SHostDialog 的派生类中处理了一个消息,如果没有将该消息交给 SHostWnd 继续处理,可能导致 SOUI 不能正常工作。

在SHostWnd或SHostDialog的派生类中处理消息时,需要注意消息的传递链。如果你拦截了某个消息但没有让它继续传递给SHostWnd,可能会影响SOUI的正常工作。

如何正确传递消息

没有 WTL 使用经历的朋友可能想知道如何将一个消息交给 SHostWnd 继续处理。当用户在自己的消息映射表中增加一个消息处理函数,而且是插入在映射表的 CHAIN_MSG_MAP(SHostWnd)前(也应该在此之前,否则很可能就收不到消息),默认情况下会自动标志该消息已经被处理了,如此一来就不会继续交给 SHostWnd 处理,解决办法很简单,在你的消息处理函数中增加一行:

SetMsgHandled(FALSE);

有了这一行,你就不用担心你的消息处理影响到 SHostWnd 的处理了。

常见问题示例

一个典型的问题是处理Timer消息导致SOUI动画停止工作。这是因为Timer消息被拦截,没有传递给SOUI的动画系统。解决方法就是在Timer处理函数中添加SetMsgHandled(FALSE)

很多朋友在使用 SOUI 时处理自己的 Timer,结果导致 SOUI 中的动画不动了,就是因为这个原因:SOUI 内部需要处理自己的定时器消息,但它被最外层的消息映射表截断了。

最佳实践

  1. 在消息映射表中,将自定义消息处理放在CHAIN_MSG_MAP(SHostWnd)之前
  2. 需要继续传递消息时,使用SetMsgHandled(FALSE)
  3. 对于Timer等系统消息,要特别注意不要影响SOUI的内部功能

总结

了解这些WTL相关的基础知识,将有助于你: - 更好地理解SOUI的消息处理机制 - 避免常见的消息处理问题 - 正确处理消息传递链

基本上会上面这样一点 WTL 相关的知识就可以玩转 SOUI 了。