跳转至

SHostDialog

概述

SHostDialog 是 SOUI 框架中专门用于创建模态和非模态对话框的类,它继承自 SHostWnd,在保留原有宿主窗口功能的基础上,增加了对话框特有的功能。

架构设计

graph TD
    A[CSimpleWnd] --> B[SHostWnd]
    B --> C[SHostDialog]
    C --> D[自定义对话框]

核心特性

1. 对话框类型

class SOUI_EXP SHostDialog : public SHostWnd
{
public:
    // 构造函数
    SHostDialog(LPCTSTR pszXmlName = NULL);

    // 模态对话框
    INT_PTR DoModal(HWND hParent = NULL);

    // 非模态对话框
    BOOL Create(HWND hParent = NULL);
};

2. 消息处理

// 对话框消息处理
class CMyDialog : public SHostDialog
{
protected:
    // 初始化处理
    BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

    // 关闭处理
    void OnCancel();
    void OnOK();

    // 消息映射
    BEGIN_MSG_MAP_EX(CMyDialog)
        MSG_WM_INITDIALOG(OnInitDialog)
        MSG_WM_CLOSE(OnClose)
        CHAIN_MSG_MAP(SHostDialog)
        REFLECT_NOTIFICATIONS_EX()
    END_MSG_MAP()
};

使用指南

1. 创建模态对话框

// 对话框定义
class CSettingsDialog : public SHostDialog
{
public:
    CSettingsDialog() 
        : SHostDialog(_T("LAYOUT:XML_SETTINGS_DLG")) 
    {}

protected:
    // 初始化对话框
    BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam) {
        // 初始化控件
        m_pEditName = FindChildByName2<SEdit>(L"edit_name");
        m_pCbxType = FindChildByName2<SComboBox>(L"cbx_type");

        return TRUE;
    }

    // 确定按钮处理
    void OnOK() {
        if (m_pEditName && m_pEditName->GetWindowTextLength() == 0) {
            SMessageBox(m_hWnd, _T("请输入名称"), _T("提示"), MB_OK | MB_ICONWARNING);
            return;
        }
        EndDialog(IDOK);
    }

    // 取消按钮处理
    void OnCancel() {
        EndDialog(IDCANCEL);
    }

private:
    SEdit* m_pEditName;
    SComboBox* m_pCbxType;
};

// 使用示例
void ShowSettingsDialog() {
    CSettingsDialog dlg;
    if (IDOK == dlg.DoModal()) {
        // 处理确定操作
    }
}

2. 创建非模态对话框

class CInfoDialog : public SHostDialog
{
public:
    CInfoDialog() 
        : SHostDialog(_T("LAYOUT:XML_INFO_DLG")) 
    {}

    // 创建非模态对话框
    BOOL CreateDialog(HWND hParent) {
        return Create(hParent);
    }

protected:
    void OnClose() {
        DestroyWindow();
    }

    BEGIN_MSG_MAP_EX(CInfoDialog)
        MSG_WM_CLOSE(OnClose)
        CHAIN_MSG_MAP(SHostDialog)
    END_MSG_MAP()
};

// 使用示例
CInfoDialog* ShowInfoDialog(HWND hParent) {
    CInfoDialog* pDlg = new CInfoDialog();
    if (pDlg->CreateDialog(hParent)) {
        return pDlg;
    }
    delete pDlg;
    return NULL;
}

3. 对话框布局

<SOUI title="设置对话框" 
      width="400" 
      height="300" 
      appwin="0" 
      resizable="0"
      translucent="1">
    <root skin="_skin.sys.wnd.bkgnd">
        <caption pos="0,0,-0,30">
            <text pos="10,8">设置</text>
            <imgbtn id="2" 
                    skin="_skin.sys.btn.close"
                    pos="-45,0" 
                    tip="关闭"/>
        </caption>

        <window pos="10,40,-10,-50">
            <!-- 对话框内容 -->
            <text pos="10,10">名称:</text>
            <edit name="edit_name" 
                  pos="100,10,-10,35"/>

            <text pos="10,50">类型:</text>
            <combobox name="cbx_type" 
                     pos="100,50,-10,75"/>
        </window>

        <!-- 按钮区域 -->
        <window pos="10,-40,-10,-10">
            <button name="btn_ok" 
                    pos="-150,-30,-80,0" 
                    class="normalbtn">确定</button>
            <button name="btn_cancel" 
                    pos="-70,-30,0,0" 
                    class="normalbtn">取消</button>
        </window>
    </root>
</SOUI>

高级特性

1. 对话框数据交换

class CDataDialog : public SHostDialog
{
public:
    // 对话框数据结构
    struct DialogData {
        SStringT strName;
        int nType;
        BOOL bEnabled;
    };

    void SetData(const DialogData& data) {
        m_data = data;
    }

    const DialogData& GetData() const {
        return m_data;
    }

protected:
    // 数据到控件
    void DataToUI() {
        if (m_pEditName) 
            m_pEditName->SetWindowText(m_data.strName);
        if (m_pCbxType)
            m_pCbxType->SetCurSel(m_data.nType);
        if (m_pChkEnabled)
            m_pChkEnabled->SetCheck(m_data.bEnabled);
    }

    // 控件到数据
    void UIToData() {
        if (m_pEditName)
            m_data.strName = m_pEditName->GetWindowText();
        if (m_pCbxType)
            m_data.nType = m_pCbxType->GetCurSel();
        if (m_pChkEnabled)
            m_data.bEnabled = m_pChkEnabled->IsChecked();
    }

private:
    DialogData m_data;
};

2. 对话框状态管理

class CStateDialog : public SHostDialog
{
protected:
    // 保存对话框状态
    void SaveState() {
        SStringT strConfig;

        // 保存窗口位置
        CRect rcWnd;
        GetWindowRect(&rcWnd);
        strConfig.Format(_T("pos:%d,%d,%d,%d"),
            rcWnd.left, rcWnd.top,
            rcWnd.right, rcWnd.bottom);

        // 保存选项状态
        if (m_pCbxType)
            strConfig.AppendFormat(_T(";type:%d"), m_pCbxType->GetCurSel());

        // 写入配置
        SStringT strApp = _T("DialogState");
        WritePrivateProfileString(strApp, _T("MainDlg"), 
                                strConfig, _T("config.ini"));
    }

    // 恢复对话框状态
    void LoadState() {
        TCHAR szBuf[MAX_PATH] = {0};
        SStringT strApp = _T("DialogState");
        GetPrivateProfileString(strApp, _T("MainDlg"), 
                              _T(""), szBuf, MAX_PATH, _T("config.ini"));

        SStringT strConfig = szBuf;
        // 解析配置...
    }
};

最佳实践

1. 对话框基类

class CBaseDialog : public SHostDialog
{
protected:
    // 通用初始化
    BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam) {
        // 初始化基础功能
        InitControls();
        LoadState();
        return TRUE;
    }

    // 通用清理
    void OnFinalMessage(HWND hWnd) {
        SaveState();
        __super::OnFinalMessage(hWnd);
    }

    // 公共事件处理
    bool OnCommonCommand(EventArgs* e) {
        EventCmd* eCmd = sobj_cast<EventCmd>(e);
        if (!eCmd) return false;

        SStringW strName = eCmd->sender->GetName();
        if (strName == L"btn_ok")
            OnOK();
        else if (strName == L"btn_cancel")
            OnCancel();

        return true;
    }

    EVENT_MAP_BEGIN()
        EVENT_HANDLER(EventCmd::EventID, OnCommonCommand)
    EVENT_MAP_END()
};

2. 对话框工厂

class CDialogFactory
{
public:
    // 创建对话框
    static SHostDialog* CreateDialog(const SStringT& strType) {
        if (strType == _T("settings"))
            return new CSettingsDialog();
        else if (strType == _T("info"))
            return new CInfoDialog();
        return NULL;
    }

    // 显示模态对话框
    static INT_PTR ShowModalDialog(const SStringT& strType, 
                                 HWND hParent = NULL) {
        SAutoRefPtr<SHostDialog> pDlg(CreateDialog(strType));
        if (!pDlg) return IDCANCEL;
        return pDlg->DoModal(hParent);
    }
};

注意事项

  1. 内存管理
  2. 非模态对话框需要正确处理内存释放
  3. 使用智能指针管理对话框对象
  4. 注意子控件的生命周期

  5. 状态管理

  6. 合理保存和恢复对话框状态
  7. 处理窗口位置和大小变化
  8. 管理控件数据

  9. 性能优化

  10. 避免频繁创建销毁对话框
  11. 合理使用缓存机制
  12. 优化数据交换过程

调试技巧

// 对话框调试助手
class CDialogDebugger
{
public:
    static void TraceDialogInfo(SHostDialog* pDlg) {
        STRACE(_T("Dialog[%s] State:"), pDlg->GetWindowText());

        // 输出窗口信息
        CRect rcWnd;
        pDlg->GetWindowRect(&rcWnd);
        STRACE(_T("Position: (%d,%d,%d,%d)"), 
               rcWnd.left, rcWnd.top, 
               rcWnd.right, rcWnd.bottom);

        // 输出控件状态
        // ...
    }
};