跳转至

SHostWnd

概述

SOUI 宿主窗口(SHostWnd)是 SOUI 框架中一个核心组件,它作为 DirectUI 系统与 Windows 原生窗口系统的桥梁,实现了:

  • 托管 DirectUI 控件树
  • 处理 Windows 消息
  • 管理渲染过程
  • 提供事件机制

宿主窗口层次

graph TD
    A[CSimpleWnd] --> B[SHostWnd]
    B --> C[DirectUI Root]
    C --> D[DirectUI Controls]

核心功能

1. 窗口创建与销毁

class SHostWnd : public CSimpleWnd
{
public:
    // 创建窗口
    BOOL Create(LPCTSTR lpszResName, int nPosX = CW_USEDEFAULT, int nPosY = CW_USEDEFAULT,
               int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT);

    // 从资源 ID 创建窗口               
    BOOL CreateEx(HWND hWndParent, DWORD dwStyle = 0, DWORD dwExStyle = 0,
                 int nID = 0);
};

使用示例

class CMainDlg : public SHostWnd
{
public:
    CMainDlg() : SHostWnd(_T("LAYOUT:XML_MAINWND")) {}

    void OnInit() {
        // 初始化窗口
        Create(_T("main_window"), 
               CW_USEDEFAULT, CW_USEDEFAULT, 
               800, 600);
    }
};

2. 消息处理

SHostWnd 提供了完整的 Windows 消息处理机制:

// 消息映射示例
BOOL OnCreate(LPCREATESTRUCT lpCreateStruct);
void OnDestroy();
void OnPaint(HDC dc);
void OnSize(UINT nType, CSize size);
LRESULT OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam);

消息转发机制

graph LR
    A[Windows Message] --> B[SHostWnd]
    B --> C[Message Map]
    C --> D[Event System]
    D --> E[DirectUI Controls]

3. 渲染管理

宿主窗口负责管理整个 DirectUI 树的渲染过程:

void OnPaint(HDC dc) {
    SPainter painter;
    BeforePaint(dc, painter);

    // 渲染 DirectUI 控件树
    OnRedraw(dc, NULL);

    AfterPaint(dc, painter);
}

4. 布局管理

// 布局更新
void UpdateLayout();

// 调整窗口大小
void UpdateAutoSizeCount();

// 获取客户区大小
CRect GetClientRect() const;

高级特性

1. 动画支持

// 动画控制
class SOUI_EXP IAnimation {
    virtual void Start(IAnimationListener* pListener) = 0;
    virtual void Stop() = 0;
};

2. 透明窗口

// 设置窗口透明度
void SetWindowAlpha(BYTE byAlpha);

// 开启分层窗口
BOOL EnableLayeredWindow(BOOL bEnable);

3. 事件系统

// 事件映射
EVENT_MAP_BEGIN()
    EVENT_ID_COMMAND(btnID, OnBtnClick)
    EVENT_NAME_HANDLER("edit", EventRENotify::EventID, OnEditNotify)
EVENT_MAP_END()

最佳实践

1. 窗口创建

class CCustomWindow : public SHostWnd
{
public:
    CCustomWindow(LPCTSTR pszResName = NULL) 
        : SHostWnd(pszResName) 
    {
        m_bLayeredWindow = TRUE;  // 启用分层窗口
    }

protected:
    // 处理窗口初始化
    void OnInit() {
        // 加载布局资源
        SetXMLFromRes(L"LAYOUT:XML_MAINWND");

        // 设置窗口属性
        SetWindowLongPtr(GWL_STYLE, 
            GetWindowLongPtr(GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    }

    // 处理窗口销毁
    void OnFinalMessage(HWND hWnd) {
        __super::OnFinalMessage(hWnd);
        delete this;
    }

    // 注册消息处理
    BEGIN_MSG_MAP_EX(CCustomWindow)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        MSG_WM_SIZE(OnSize)
        CHAIN_MSG_MAP(SHostWnd)
        REFLECT_NOTIFICATIONS_EX()
    END_MSG_MAP()
};

2. 窗口优化

// 缓存管理
void EnableCache(BOOL bEnable) {
    GetRoot()->EnableCache(bEnable);
}

// 渲染优化
void OptimizeDrawing() {
    // 开启双缓存
    ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

    // 设置更新区域
    CRect rcClient;
    GetClientRect(&rcClient);
    InvalidateRect(rcClient);
}

3. 事件处理

// 事件处理示例
class CMainWindow : public SHostWnd
{
protected:
    // 按钮点击事件
    void OnBtnClick(EventArgs *e) {
        EventCmd *eCmd = sobj_cast<EventCmd>(e);
        if(eCmd) {
            // 处理命令事件
        }
    }

    // 编辑框通知
    void OnEditNotify(EventArgs *e) {
        EventRENotify *eNotify = sobj_cast<EventRENotify>(e);
        if(eNotify) {
            // 处理编辑框通知
        }
    }

    // 注册事件处理
    EVENT_MAP_BEGIN()
        EVENT_NAME_COMMAND(L"btnOK", OnBtnClick)
        EVENT_NAME_HANDLER(L"editContent", EventRENotify::EventID, OnEditNotify)
    EVENT_MAP_END()
};

注意事项

  1. 窗口生命周期
  2. 正确处理窗口创建和销毁
  3. 管理子窗口资源
  4. 清理事件订阅

  5. 消息处理

  6. 避免阻塞消息循环
  7. 合理使用消息过滤
  8. 注意消息优先级

  9. 性能优化

  10. 合理使用缓存机制
  11. 控制重绘区域
  12. 优化事件处理

调试技巧

// 调试辅助类
class CWindowDebugger {
public:
    static void DumpWindowInfo(SHostWnd* pWnd) {
        STRACE(_T("Window Handle: 0x%08x"), pWnd->m_hWnd);
        STRACE(_T("Window Style: 0x%08x"), GetWindowLong(pWnd->m_hWnd, GWL_STYLE));
        STRACE(_T("Window Rect: (%d,%d,%d,%d)"), 
               pWnd->m_rcWindow.left, pWnd->m_rcWindow.top,
               pWnd->m_rcWindow.right, pWnd->m_rcWindow.bottom);
    }
};

示例代码

完整的窗口实现示例

class CMainWindow : public SHostWnd
{
public:
    CMainWindow() : SHostWnd(_T("LAYOUT:XML_MAINWND")) 
    {
        m_bLayeredWindow = TRUE;
    }

    ~CMainWindow() {}

protected:
    // 窗口初始化
    BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam) {
        // 初始化控件
        m_pTabMain = FindChildByName2<STabCtrl>(L"tab_main");
        m_pEditInput = FindChildByName2<SEdit>(L"edit_input");

        // 注册事件处理
        if(m_pTabMain) {
            m_pTabMain->GetEventSet()->subscribeEvent(
                EVT_TAB_SELCHANGED, 
                Subscriber(&CMainWindow::OnTabChanged, this));
        }

        return TRUE;
    }

    // 事件处理
    bool OnTabChanged(EventArgs *e) {
        EventTabSelChanged *ev = sobj_cast<EventTabSelChanged>(e);
        if(ev) {
            // 处理标签切换
            UpdateLayout();
            return true;
        }
        return false;
    }

    // 消息映射
    BEGIN_MSG_MAP_EX(CMainWindow)
        MSG_WM_INITDIALOG(OnInitDialog)
        MSG_WM_CLOSE(OnClose)
        CHAIN_MSG_MAP(SHostWnd)
        REFLECT_NOTIFICATIONS_EX()
    END_MSG_MAP()

    // 事件映射
    EVENT_MAP_BEGIN()
        EVENT_NAME_COMMAND(L"btn_ok", OnOKClick)
        EVENT_NAME_COMMAND(L"btn_cancel", OnCancelClick)
    EVENT_MAP_END()

private:
    STabCtrl* m_pTabMain;
    SEdit* m_pEditInput;
};

参考资料