实现圆角窗口¶
Warning
The current page still doesn't have a translation for this language.
You can read it through google translate.
在SOUI中实现圆角窗口是一个常见的需求。本文将介绍如何在非半透明窗口中实现圆角效果。
实现方案¶
半透明窗口的简单方案¶
如果SOUI的宿主窗口不包含子窗口,可以直接使用窗口的半透明属性:
<window translucent="1">
非半透明窗口的解决方案¶
当窗口中包含子窗口时,半透明属性可能会导致子窗口显示异常。这种情况下,我们需要使用SetWindowRgn
来实现圆角效果。
专业实现代码¶
以下是一个专门用于实现圆角窗口的模板类:
template <class T>
class CWHRoundRectFrameHelper
{
protected:
SIZE m_sizeWnd;
void OnSize(UINT nType, CSize size)
{
T *pT = static_cast<T*>(this);
if (nType == SIZE_MINIMIZED)
return;
if (size == m_sizeWnd)
return;
CRect rcWindow, rcClient;
CRgn rgnWindow, rgnMinus, rgnAdd;
pT->CSimpleWnd::GetWindowRect(rcWindow);
pT->CSimpleWnd::GetClientRect(rcClient);
pT->CSimpleWnd::ClientToScreen(rcClient);
rcClient.OffsetRect(- rcWindow.TopLeft());
// 创建基本区域
rgnWindow.CreateRectRgn(rcClient.left, rcClient.top + 2,
rcClient.right, rcClient.bottom - 2);
// 添加上边圆角
rgnAdd.CreateRectRgn(rcClient.left + 2, rcClient.top,
rcClient.right - 2, rcClient.top + 1);
rgnWindow.CombineRgn(rgnAdd, RGN_OR);
// 添加下边圆角
rgnAdd.OffsetRgn(0, rcClient.Height() - 1);
rgnWindow.CombineRgn(rgnAdd, RGN_OR);
// 添加上边过渡区
rgnAdd.SetRectRgn(rcClient.left + 1, rcClient.top + 1,
rcClient.right - 1, rcClient.top + 2);
rgnWindow.CombineRgn(rgnAdd, RGN_OR);
// 添加下边过渡区
rgnAdd.OffsetRgn(0, rcClient.Height() - 3);
rgnWindow.CombineRgn(rgnAdd, RGN_OR);
// 设置窗口区域
pT->CSimpleWnd::SetWindowRgn(rgnWindow);
pT->SetMsgHandled(FALSE);
m_sizeWnd = size;
}
public:
BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)
{
BOOL bHandled = TRUE;
switch(dwMsgMapID)
{
case 0:
if (uMsg == WM_SIZE)
{
OnSize((UINT)wParam,
_WTYPES_NS::CSize(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam)));
lResult = 0;
}
break;
}
return FALSE;
}
};
使用示例¶
在SOUI对话框中使用圆角窗口模板类:
class CFuckDialog : public SHostDialog,
public CWHRoundRectFrameHelper<CFuckDialog>
{
BEGIN_MSG_MAP_EX(CMainDlg)
// 重要:必须在SHostDialog之前
CHAIN_MSG_MAP(CWHRoundRectFrameHelper<CFuckDialog>)
CHAIN_MSG_MAP(SHostDialog)
REFLECT_NOTIFICATIONS_EX()
END_MSG_MAP()
};
注意事项¶
- 圆角实现基于
SetWindowRgn
API - 需要在窗口大小变化时重新设置区域
- 消息映射表中,圆角处理必须在
CHAIN_MSG_MAP(SHostDialog)
之前
优点与局限¶
优点¶
- 可以与子窗口共存
- 不影响窗口性能
- 可以精确控制圆角大小
局限¶
- 只能实现规则的圆角形状
- 不支持不规则的异形窗口
最佳实践¶
- 根据实际需求选择合适的方案
- 无子窗口时使用半透明属性
-
有子窗口时使用
SetWindowRgn
-
注意性能优化
- 缓存窗口大小避免重复计算
- 仅在必要时更新窗口区域