VC++界面编程之--阴影窗口的实现详解

对于我们这些控件狂来说,窗口阴影也是一个必不可少的实现需求。虽说其没多大用,但对于增加窗口立体感来说,那是挺有帮助的。
我实现了一个类似于360界面的阴影效果,其可以支持正常窗口,也支持半透明窗口。
阴影窗口对于正常窗口和半透明窗口,有区别么?且让我慢慢写来:)


阴影窗口的实现原理,简单来讲:就是在主窗口创建时,创建一个子窗口,吸附于主窗口的底部。然后在子窗口上做一个带半透明阴影效果的描绘。
以下代码是阴影窗口在父窗口的创建代码,是不是很简单?
[html] view plaincopy
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)  
{  
    m_Shadow.Create(m_hWnd);  
    m_Shadow.SetShadowSize(8);  
  
    return TRUE;  
}  
下面是阴影窗口实现步骤:
1. 在阴影窗口创建时,只设定阴影窗口的样式为WS_VISIBLE,我们这里不能用WS_CHILD,否则阴影窗口就跑到主窗口里面去了。
[cpp] view plaincopy
// Create shadow window.  
HWND Create(const HWND wndParent)  
{  
    ATLASSERT( ::IsWindow(wndParent) );  
    m_hParentWnd = wndParent;  
    CRect rc(1, 1, 1, 1);  
    return CWindowImpl<CThemedShadowWnd, CWindow, CControlWinTraits>::Create(0, rc, NULL, WS_VISIBLE, NULL);  
}  


2. 在阴影窗口执行WM_CREATE消息时,修改其样式为WS_EX_LAYERED | WS_EX_TRANSPARENT,注意这两个样式都要要。WS_EX_TRANSPARENT是让窗口无法接收点击消息,你总不想你的窗口阴影可以被用户点击且激活吧:)
[cpp] view plaincopy
SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);  
ModifyStyleEx(WS_EX_TOPMOST, WS_EX_NOACTIVATE);  
3. 与此同时,阴影窗口注册父窗口的消息处理回调函数,此举是为了获取父窗口的移动、重绘和隐藏等重要消息。因为阴影窗口要跟随着父窗口的状态改变而改变。
[cpp] view plaincopy
// Set parent window original processing.  
m_OriParentProc = ::GetWindowLong(m_hParentWnd, GWL_WNDPROC);  
::SetWindowLong(m_hParentWnd, GWL_WNDPROC, (LONG)ParentProc);  


回调函数要做的事情很简单,吸附于父窗口之下,像个小尾巴一样:
[cpp] view plaincopy
// Get parent message.  
static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
    // Find the shadow window pointer via parent window handle.  
    ATLASSERT( m_szShadowWindows.find(hwnd) != m_szShadowWindows.end() );  
    CThemedShadowWnd *pThis = m_szShadowWindows[hwnd];  
    WNDPROC pDefProc        = (WNDPROC)pThis->m_OriParentProc;  
  
    switch(uMsg)  
    {  
    case WM_ERASEBKGND:  
    case WM_PAINT:  
    case WM_MOVE:  
    case WM_ACTIVATE:  
    case WM_NCACTIVATE:  
        {  
            if (::IsWindowVisible(hwnd))   
            {   
                pThis->AdjustWindowPos();   
            }  
            break;  
        }  
    case WM_DESTROY:  
        {  
            // Destroy the shadow window.  
            pThis->DestroyWindow();    
            break;  
        }  
    case WM_NCDESTROY:  
        {  
            // Remove shadow window from map.  
            m_szShadowWindows.erase(hwnd);    
            break;  
        }  
    case WM_SHOWWINDOW:  
        {  
            // the window is being hidden  
            if (!wParam)      
            {  
                pThis->ShowWindow(SW_HIDE);  
            }  
            else  
            {  
                pThis->ShowWindow(SW_SHOW);  
            }  
            break;  
        }  
    default:  
        {  
            break;  
        }  
    }  
  
    return pDefProc(hwnd, uMsg, wParam, lParam);  
}  
好了,窗口消息机制处理完了,就要处理阴影画法了,我这里用的是GDI+的画法,如果有童鞋觉得效果不够好,可以尝试多改改参数配置,以达到理想效果:
[cpp] view plaincopy
// Create shadow brush.  
PathGradientBrush brShadow(m_ShadowPath.m_pPath);  
Color clrShadow[3] = {Color::Transparent, Color(255, 0, 0, 0), Color(255, 0, 0, 0)};  
int nCount = 3;  
  
REAL szPos[3] = {0.0F, 0.05F, 1.0F};  
brShadow.SetInterpolationColors(clrShadow, szPos, nCount);  
  
// Draw shadow.  
rcShadow.Width  = rcShadow.Width - m_nShadowSize - m_nBlankArea;  
rcShadow.Height = rcShadow.Height - m_nShadowSize - m_nBlankArea;  
graphics.ExcludeClip(rcShadow);  
graphics.FillPath(&brShadow, m_ShadowPath.m_pPath);  


注意我这里排除了一部分的阴影部分,那是为透明窗口制作的,排除的效果图如下,阴影窗口只显示在矩形的右下角,而其他地方是透明的。


如果我不排除一部分阴影区域,那么透明的窗口效果将变得很难看,如下图,透明背景被阴影遮盖了,这显然不符合美学的要求。


如果你的窗口的角是椭圆的,你可能还需要增宽阴影的显示区域,那么可以用如下函数进行阴影的宽度增长:
[cpp] view plaincopy
// Set blank area right position.  
void SetRightOffsetArea(const int nRightPos)  
{  
    m_nBlankArea = nRightPos;  
    if (nRightPos < 0)  
    {  
        m_nBlankArea = 1;  
    }  
}  

 


阴影窗口免费实例代码下载:http://download.csdn.net/detail/renstarone/6267677

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浮点运算是计算机中一种常见的数值计算方法,但在某些场景中,如嵌入式系统或低成本设备中,使用浮点数的硬件支持可能较差。此时,定点编程可以作为一种替代方案来处理数值计算。 定点编程是一种使用固定的小数点位置来表示数值的编程方法。我们可以选择一个合适的定点位置,将浮点数转化为定点数来进行运算。例如,我们可以选择一个定点位置为2的定点数表示方法,其中整数部分占据16位,小数部分占据16位。这样,定点数10.5将被表示为10500。 在定点编程中,我们需要注意以下几个技巧: 1. 定点数的运算:定点数的加减法运算与整数运算相同,只需保持小数点位置不变即可。乘法和除法运算需要特殊处理,可通过移位操作模拟乘以或除以2的幂次方的运算。 2. 范围和精度控制:定点数的范围和精度取决于选择的小数点位置。选择小数点位置较高可以提高精度,但会减小表示的范围,选择小数点位置较低则相反。需要根据具体需求权衡范围和精度的平衡。 3. 数据类型转换:在定点编程中,需要注意在不同数据类型之间进行转换。如果需要将定点数转换为整数,可以通过移位操作和取整来实现。如果需要将整数转换为定点数,可以通过移位操作和适当的缩放来实现。 4. 数值截断和溢出处理:定点编程中,数值的截断和溢出是需要注意的问题。如取整操作可能导致数值的丢失,而乘法或加法可能导致数值的溢出。需要根据具体情况进行合适的处理,如舍入或截断操作来避免数值的损失或溢出。 总之,定点编程是一种用于替代浮点运算的数值计算方法。通过选择合适的小数点位置,使用定点编程可以在某些硬件受限的环境中实现高效的数值计算。需要注意的是,定点编程需要根据具体场景进行适当的调整和处理,以实现所需的范围和精度,并避免数值截断和溢出的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值