在SOUI中使用真窗口¶
Warning
The current page still doesn't have a translation for this language.
You can read it through google translate.
在DirectUI系统中,有时需要在DUI窗口中嵌入带有窗口句柄的传统Windows控件(真窗口)。本文将介绍如何在SOUI中优雅地管理和使用真窗口。
概念介绍¶
什么是真窗口?¶
- 具有窗口句柄(HWND)的Windows控件
- 传统Win32控件
- MFC/ATL控件等
为什么需要真窗口?¶
- 使用特定的第三方控件
- 集成现有的Windows控件
- 特殊功能需要使用原生窗口
SRealWnd控件¶
SOUI提供了SRealWnd
控件来管理真窗口:
- 继承自
SWindow
- 支持SOUI的布局系统
- 管理真窗口的生命周期
- 处理窗口状态同步
实现IRealWndHandler接口¶
接口定义¶
struct IRealWndHandler : public IObjRef {
// 创建真窗口
virtual HWND OnRealWndCreate(SRealWnd *pRealWnd) = NULL;
// 销毁真窗口
virtual void OnRealWndDestroy(SRealWnd *pRealWnd) = NULL;
// 初始化窗口
virtual BOOL OnRealWndInit(SRealWnd *pRealWnd) = NULL;
// 调整窗口大小
virtual BOOL OnRealWndSize(SRealWnd *pRealWnd) = NULL;
};
实现示例¶
class CSouiRealWndHandler : public TObjRefImpl2<IRealWndHandler, CSouiRealWndHandler> {
public:
// 创建真窗口
virtual HWND OnRealWndCreate(SRealWnd *pRealWnd) {
const SRealWndParam ¶m = pRealWnd->GetRealWndParam();
if(param.m_strClassName == _T("button")) {
CButton *pbtn = new CButton;
pbtn->Create(param.m_strWindowName,
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
CRect(0,0,0,0),
CWnd::FromHandle(pRealWnd->GetContainer()->GetHostHwnd()),
pRealWnd->GetID());
pRealWnd->SetData(pbtn);
return pbtn->m_hWnd;
}
return 0;
}
// 销毁真窗口
virtual void OnRealWndDestroy(SRealWnd *pRealWnd) {
const SRealWndParam ¶m = pRealWnd->GetRealWndParam();
if(param.m_strClassName == _T("button")) {
CButton *pbtn = (CButton*)pRealWnd->GetData();
if(pbtn) {
pbtn->DestroyWindow();
delete pbtn;
}
}
}
// 初始化和大小调整(默认由SOUI处理)
virtual BOOL OnRealWndInit(SRealWnd *pRealWnd) { return FALSE; }
virtual BOOL OnRealWndSize(SRealWnd *pRealWnd) { return FALSE; }
};
XML布局配置¶
<SOUI title="SOUI-DEMO" width="600" height="400" appwin="1" ncRect="5,5,5,5" resize="1">
<root skin="skin.bkframe" cache="1">
<caption pos="0,0,-0,29">
<text pos="11,9">带真窗口的示例</text>
</caption>
<window pos="0,29,-0,-0">
<!-- 定义真窗口 -->
<realwnd pos="10,10,-10,-10"
name="mfcbtn"
wndclass="button"
id="100"
wndname="MFC Button"/>
</window>
</root>
</SOUI>
realwnd标签属性¶
- pos:位置和大小
- name:控件名称
- wndclass:真窗口的类名
- id:控件ID
- wndname:窗口标题
消息处理¶
在主窗口中处理真窗口消息¶
class CMainDlg : public SOUI::SHostDialog {
protected:
// 处理按钮点击
void OnBtnClick(UINT uNotifyCode, int nID, HWND wndCtl) {
if(uNotifyCode == BN_CLICKED && nID == 100) {
SMessageBox(m_hWnd,
_T("真窗口按钮被点击!"),
_T("提示"),
MB_OK|MB_ICONINFORMATION);
}
}
// 消息映射
BEGIN_MSG_MAP_EX(CMainDlg)
MSG_WM_COMMAND(OnBtnClick)
CHAIN_MSG_MAP(SOUI::SHostDialog)
REFLECT_NOTIFICATIONS_EX()
END_MSG_MAP()
};
使用注意事项¶
1. 半透明限制¶
- 包含真窗口的SOUI窗口不能设置
translucent="1"
- 真窗口在半透明窗口上无法正常显示
- 此限制也适用于IE控件等
2. 生命周期管理¶
- 正确实现创建和销毁接口
- 注意内存泄漏
- 保持窗口状态同步
3. 性能考虑¶
- 适度使用真窗口
- 注意窗口重绘效率
- 合理处理消息
最佳实践¶
- 真窗口的选择
- 优先使用SOUI原生控件
- 必要时才使用真窗口
-
注意控件的兼容性
-
布局管理
- 合理设置位置和大小
- 考虑窗口重绘影响
-
正确处理Z序
-
事件处理
- 使用合适的消息映射
- 注意消息传递顺序
- 处理各类窗口状态
调试技巧¶
-
窗口层级检查
// 在创建时验证父窗口 HWND hParent = pRealWnd->GetContainer()->GetHostHwnd(); ASSERT(::IsWindow(hParent));
-
位置验证
// 检查窗口位置 CRect rcReal; ::GetWindowRect(hRealWnd, &rcReal); ASSERT(!rcReal.IsRectEmpty());
-
消息跟踪
// 添加消息跟踪 TRACE(_T("Real window message: %d\n"), message);
总结¶
通过SOUI的SRealWnd
控件,我们可以: - 方便地集成传统Windows控件 - 保持SOUI的布局特性 - 统一管理窗口生命周期 - 实现更丰富的界面功能