MFC笔记:关于透明和渐变

同样是菜单项目用到的,本来想做半透明和渐变的菜单,但后来由于各种原因只能放弃,简单记录一下要点,以备以后再用。

1、CDC画半透明(用于菜单项选中时候的选择色)


int nAlpha = 100; 
// 透明度,在0~254之间取值,越大越不透明 
BLENDFUNCTION stBlend = {AC_SRC_OVER, 0, nAlpha, 0}; 
                    
CDC dcAlphaRect;
CBitmap bmpAlphaRect;
                    
dcAlphaRect.CreateCompatibleDC(pDC);
                    

bmpAlphaRect.CreateCompatibleBitmap(pDC,selRect.Width(),selRect.Height());
CBitmap* pOld_Bitmap = dcAlphaRect.SelectObject(&bmpAlphaRect);
dcAlphaRect.FillSolidRect( 0, 0, selRect.Width(), selRect.Height(), COLOR_SEL );

AlphaBlend(pDC->m_hDC,
            selRect.left, selRect.top, 
            selRect.Width(), selRect.Height(), 
            dcAlphaRect.m_hDC,
            0,0, 
            selRect.Width(), selRect.Height(),
            stBlend); 

dcAlphaRect.SelectObject(pOld_Bitmap);
dcAlphaRect.DeleteDC();
bmpAlphaRect.DeleteObject();



2、窗体透明

ModifyStyleEx(0, WS_EX_LAYERED);
SetLayeredWindowAttributes(0,100,LWA_ALPHA);
  以上代码写在OnInitDialog函数中 ModifyStyleEx ( 0 ,  WS_EX_LAYERED ) ;为窗体添加运行透明属性,而 SetLayeredWindowAttributes则是设置透明度。 LWA_ALPHA表示指定第二个参数为透明度,0~254之间,越大越不透明。参数改为 LWA_COLORKEY则表示第一个参数指定的颜色变为透明。
  

ModifyStyleEx(0, WS_EX_LAYERED);
COLORREF crKey = RGB(160, 160, 160);
SetLayeredWindowAttributes(crKey,100,LWA_COLORKEY | LWA_ALPHA);

  如果将两种参数合并使用,那么颜色值为crKey的地方将变为全透明,并且鼠标是可以穿透过该区域的,而其它地方根据bAlpha参数确定透明度。温馨提示,如果将RGB设置为255,255,255 那么你将连标题框都点击不了。

关于分层窗体和透明窗体的博文,介绍的很深入:http://blog.163.com/ac_bc/blog/static/601647520119475322869/


3、菜单的背景透明(HOOK)

DWORD menuStyle = (DWORD)GetWindowLongPtrW(pWPS->hwnd, GWL_EXSTYLE);
SetWindowLongPtrW(pWPS->hwnd, GWL_EXSTYLE, menuStyle | WS_EX_LAYERED);
SetLayeredWindowAttributes(pWPS->hwnd, 0, 100, LWA_ALPHA);

  以上这段代码写在处理菜单的窗口过程MenuWndProc中的case WM_CREATE:,判断是否是菜单的创建下。
  但出现了一个非常奇怪的现象。我用的是Win7系统,一开始无论用别人程序还是自己程序,菜单都无法透明,整个菜单内容都没了,只剩一个背景。退出程序后一段时间,整个屏幕会黑屏闪一下,然后闪现菜单,之后又恢复正常。
  并且打开程序并多次召唤那个异常的菜单,整个电脑就会卡死,ctrl+alt+delete能唤出安全选项界面,但点击任何选项都没有办法实现该选项的功能,只能强制重启。以致于一天强制重启不下十遍,百思不得其解。
  (ps:下载了一个别人的程序是整条菜单栏而不是右键菜单,于是乎菜单是透明了,但多次显示子菜单后还是卡死了)
  后来偶然的一次,运行完程序后,桌面Aero效果消失了,然后运行程序竟然菜单内容就回来了,再也不卡死了。估计是钩子和Aero有冲突。网上有专门代码做Aero效果的,但考虑到软件需要向下兼容,就没往下细究了。知道缘由的大大麻烦指导一下啦。

开启Aero效果相关博文 http://blog.csdn.net/polytechnic/article/details/5696797


  关于渐变,其实正常来说应该是需要GDI+的吧,但是作为一只菜鸟还没学到GDI+,所以粗略说说GDI的做法。

pDC->Rectangle(selRect); 

int r1,g1,b1; 
//读取渐变起点的颜色值
r1 = GetRValue(COLOR_BK_FROM);
g1 = GetGValue(COLOR_BK_FROM);
b1 = GetBValue(COLOR_BK_FROM);

int r2,g2,b2;
//读取渐变终点的颜色值
r2 = GetRValue(COLOR_BK_TO);
g2 = GetGValue(COLOR_BK_TO);
b2 = GetBValue(COLOR_BK_TO);

float r3,g3,b3;//菜单区域水平方向每个点RGB值应该变化的度(范围)
    
r3 = ((float)(r2-r1));  //  / (float)(itemRect.Width());
g3 = (float)(g2-g1);    //  /(float)(itemRect.Width()); 
b3 = (float)(b2-b1);    //  /(float)(itemRect.Width());

float average = r3>g3 ? (r3>b3 ? r3 : b3) : (g3>b3 ? g3 : b3);
average = average>(float)selRect.Width() ? (float)selRect.Width() : average;

r3 /= average;
g3 /= average;
b3 /= average;
  
COLORREF r,g,b;//菜单区域水平方向每个点的颜色值
CPen* m_oldpen = NULL;
    
for (int i = selRect.left;i<selRect.right;i++)
{
    r = r1+(int)r3*(i-selRect.left);
    g = g1+(int)g3*(i-selRect.left);
    b = b1+ (int)b3*(i-selRect.left);
   
    CPen m_pen (PS_SOLID,1,RGB(r,g,b));
    m_oldpen = pDC->SelectObject(&m_pen);
    pDC->MoveTo(i,selRect.top);
    pDC->LineTo(i,selRect.bottom);
}

pDC->SelectObject(m_oldpen);


  代码思路就是将RGB值分开,通过计算将颜色值的改变用线填充起来。刚开始用 r3  =   ( ( float ) ( r2 - r1 ) /   ( float ) ( itemRect . Width ( ) ) ;,但是在做菜单是还没有决定配色,要不断用颜色试效果,有时候因为itemRect比颜色跨度大,会直接变成颜色填充,而不是渐变。因此用r3 g3 b3 之间最大值,并且不大于itemRect.Width的值来算。缺点是变化量过小的时候就只有一部分是渐变,另一部分还是颜色填充。最后因为渐变配色太困难了还是放弃了。


  最后记录一个不相关的小技巧。

  在一开始想创建好字体供整体使用,但是实在找不到哪里可以获取LOGFONT结构体,所以自己创建。但是字体除了字体字号粗斜体以外,还有一些会被忽略的参数,此时可以在定义了LOGFONT了参数以后,调用CFontDialog,传入LOGFONT,查看返回的LOGFONT各参数哪些和定义的不一样,来确保LOGFONT,设置完成。 


END

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值