织梦CMS - 轻松建站从此开始!

罗索实验室

当前位置: 主页 > 杂项技术 > VC(MFC) >

一个更COOL的透明浮动窗口

落鹤生 发布于 2010-05-27 09:29 点击:次 
大家看过vccode.com上那篇文章《一个很酷COOL的透明浮动窗口》。我进行了一些改进,解决了作者在文章最后遗留下的那个问题,并实现快捷菜单功能。以下格式仿此文章的格式,并有一部分从其中摘录(偶人比较懒,嘿嘿),在此感谢作者。
TAG:

引子:

大家看过http://www.vccode.com上那篇文章《一个很酷COOL的透明浮动窗口》(http://www.vccode.com/file_show.php?id=2330)。我进行了一些改进,解决了作者在文章最后遗留下的那个问题,并实现快捷菜单功能。以下格式仿此文章的格式,并有一部分从其中摘录(偶人比较懒,嘿嘿),在此感谢作者。

正文:

摘要
本文分析了Windows环境下使用MFC实现透明窗口,以及浮动窗口的方法
关键词: 透明窗口,浮动窗口。

编译环境
WIN2000以上操作系统,VC++6.0。

技术原理
如何实现透明窗口

使用MFC的AppWizard生成一个基于对话框的工程,删除Didalog上的所有控件,并设置其附加属性Extended Styles为 Tool Window。
使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。

SetLayeredWindowAttributes的函数原型如下:

BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window
COLORREF crKey, // specifies the color key
BYTE bAlpha, // value for the blend function
DWORD dwFlags // action
);


Windows NT/2000/XP: Included in Windows 2000 and later.
Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的)
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

一些常量: 

WS_EX_LAYERED = 0x80000;
LWA_ALPHA = 0x2;
LWA_COLORKEY=0x1;  

其中dwFlags有LWA_ALPHA和LWA_COLORKEY
LWA_ALPHA被设置的话,通过bAlpha决定透明度.
LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示.
要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000).

例子代码:

  1. BOOL CFloatDlgDlg::OnInitDialog() 
  2.          CDialog::OnInitDialog(); 
  3. ///////////////////////////控制窗体大小和位置 ////////////////////////////// 
  4.          CRect rect; 
  5.          CWnd *pWnd = this->GetDesktopWindow(); 
  6.          pWnd->GetWindowRect(&rect); 
  7.          this->MoveWindow(rect.left + rect.Width() - 200, rect.top + 100, 42, 42); 
  8.          SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); 
  9.          // Add "About..." menu item to system menu. 
  10.          // IDM_ABOUTBOX must be in the system command range. 
  11.          ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
  12.          ASSERT(IDM_ABOUTBOX < 0xF000); 
  13.          CMenu* pSysMenu = GetSystemMenu(FALSE); 
  14.          if (pSysMenu != NULL) 
  15.          { 
  16.                    CString strAboutMenu; 
  17.                    strAboutMenu.LoadString(IDS_ABOUTBOX); 
  18.                    if (!strAboutMenu.IsEmpty()) 
  19.                    { 
  20.                             pSysMenu->AppendMenu(MF_SEPARATOR); 
  21.                             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
  22.                    } 
  23.          } 
  24.          // Set the icon for this dialog.  The framework does this automatically 
  25.          //  when the application’s main window is not a dialog 
  26.          SetIcon(m_hIcon, TRUE);                        // Set big icon 
  27.          SetIcon(m_hIcon, FALSE);            // Set small icon 
  28.          // TODO: Add extra initialization here 
  29. ////////////////////////以下实现窗体的透明/////////////////////////////////// 
  30.          //加入WS_EX_LAYERED扩展属性 
  31.          SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE, 
  32.                   GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000); 
  33.          HINSTANCE hInst = LoadLibrary("User32.DLL"); 
  34.          if(hInst) 
  35.          { 
  36.                   typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); 
  37.                   MYFUNC fun = NULL; 
  38.                   //取得SetLayeredWindowAttributes函数指针 
  39.                   fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes"); 
  40.                   if(fun)fun(this->GetSafeHwnd(),0,128,2); 
  41.                   FreeLibrary(hInst); 
  42.          } 
  43. ////////////////////////////////////////////////////////////////////////////////// 
  44.          ModifyStyle( WS_CAPTION, WS_MINIMIZEBOX, SWP_DRAWFRAME );//设置图标     
  45.          m_bmpBackground.LoadBitmap(IDB_FLOAT);         
  46.          return TRUE;  // return TRUE  unless you set the focus to a control 
  47. }  


如何实现浮动窗口的拖动

一般的窗体,只有鼠标位于非客户区是,才可拖动。因此,只要我们将客户区“变”为“非客户区”不就可以拖动了了吗!真是一个让人惊奇的发现!:),可是问题来了,非客户区无法加载快捷菜单,我们如何解决这一问题呢,那我们想想什么动作触发快捷菜单呢?对了,WM_RBUTTONDOWN,WM_RBUTTONUP,那拖动呢?哈哈,是WM_LBUTTONDOWN,OK,那就有方法解决了,那就是在鼠标左键按下时才将客户区“变”为“非客户区”。重载OnLButtonDown(UINT nFlags, CPoint point) ,OnLButtonUp(UINT nFlags, CPoint point),OnMouseMove(UINT nFlags, CPoint point),OnNcHitTest(CPoint point):

  1. void CFloatDlgDlg::OnLButtonDown(UINT nFlags, CPoint point) 
  2.          // TODO: Add your message handler code here and/or call default 
  3.          m_oldpoint = point; 
  4.          SetCapture(); 
  5.          drag = TRUE; 
  6.          CDialog::OnLButtonDown(nFlags, point); 
  7. void CFloatDlgDlg::OnLButtonUp(UINT nFlags, CPoint point) 
  8.          // TODO: Add your message handler code here and/or call default 
  9.          ReleaseCapture(); 
  10.          m_oldpoint = CPoint(0, 0); 
  11.          drag = FALSE; 
  12.          CDialog::OnLButtonUp(nFlags, point); 
  13.  
  14. void CFloatDlgDlg::OnMouseMove(UINT nFlags, CPoint point) 
  15.          // TODO: Add your message handler code here and/or call default 
  16.          if (m_oldpoint != CPoint(0, 0)) 
  17.          { 
  18.                   CPoint pt; 
  19.                   GetCursorPos(&pt); 
  20.                   MoveWindow(pt.x - 20, pt.y - 20, 42 ,42 ); 
  21.          } 
  22.          CDialog::OnMouseMove(nFlags, point); 
  23.  
  24. UINT CFloatDlgDlg::OnNcHitTest(CPoint point) 
  25.          // TODO: Add your message handler code here and/or call default 
  26.          //在鼠标左键按下时才将客户区“变”为“非客户区” 
  27.          if (drag) 
  28.          { 
  29.                    UINT nHitCode = CWnd::OnNcHitTest(point); 
  30.                    if (nHitCode == HTCLIENT) 
  31.                    { 
  32.                             nHitCode = HTCAPTION;                      
  33.                    } 
  34.                    return nHitCode; 
  35.          } 
  36.          else 
  37.          { 
  38.                    return CDialog::OnNcHitTest(point); 
  39.          } 
  40.          return CDialog::OnNcHitTest(point); 
  41. }  

右键菜单的实现

建立一个MENU资源,重载OnContextMenu(CWnd* pWnd, CPoint point):

  1. void CFloatDlgDlg::OnContextMenu(CWnd* pWnd, CPoint point) 
  2.          if (point.x == -1 && point.y == -1){ 
  3.                   //keystroke invocation 
  4.                    CRect rect; 
  5.                   GetClientRect(rect); 
  6.                   ClientToScreen(rect); 
  7.                   point = rect.TopLeft(); 
  8.                   point.Offset(5, 5); 
  9.          } 
  10.          CMenu menu; 
  11.          VERIFY(menu.LoadMenu(IDR_FLOAT_MENU)); 
  12.          CMenu* pPopup = menu.GetSubMenu(0); 
  13.          ASSERT(pPopup != NULL); 
  14.          CWnd* pWndPopupOwner = this
  15.          while (pWndPopupOwner->GetStyle() & WS_CHILD) 
  16.                   pWndPopupOwner = pWndPopupOwner->GetParent(); 
  17.          pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, 
  18.                   pWndPopupOwner); 
  19. }   

其他

为了美观,我将次Dialog的标题栏去掉,并且以一个图片作为它的背景,这样就实现了FlashGet的浮动窗口的效果。

背景图片

  1. BOOL CFloatDlgDlg::OnInitDialog() 
  2.          CDialog::OnInitDialog(); 
  3.          ……….//省略 
  4. //背景图片的加载 
  5.          ModifyStyle( WS_CAPTION, WS_MINIMIZEBOX, SWP_DRAWFRAME );//设置图标     
  6.          m_bmpBackground.LoadBitmap(IDB_FLOAT);         
  7.          return TRUE;  // return TRUE  unless you set the focus to a control 
  8.  
  9. //重载OnPaint() 
  10. void CFloatDlgDlg::OnPaint() 
  11.          CPaintDC dc(this); 
  12.          CRect rect; 
  13.          GetClientRect(&rect); 
  14.          CDC dcMem; 
  15.          dcMem.CreateCompatibleDC(&dc); 
  16.          BITMAP bitMap; 
  17.          m_bmpBackground.GetBitmap(&bitMap); 
  18.          CBitmap *pbmpOld=dcMem.SelectObject(&m_bmpBackground); 
  19.          dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,
  20. 0,bitMap.bmWidth,bitMap.bmHeight,SRCCOPY); 
  21. }  

以上是偶的一些大致介绍,具体请看源码,偶觉得还可以,各位大虾有什么意见提出来,大家共同探讨!
 

(秩名)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www1.rosoo.net/a/201005/9514.html]
本文出处:网络博客 作者:秩名
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容