实现带阴影弹出窗口的技术

一.问题的提出

   在WINDOWS的WINHELPER帮助系统中大量使用一类带阴影的弹出窗口, 这类窗口非常简洁,并具有立体感,它们用来显示一些只读信息.此类弹出窗口不同于一般的窗口,它们没有标题和滚动杆,但都具有带阴影的边框, 并且其窗口的大小随显示字符串多少而自动调节,当显示信息弹出之后,任何来自键盘或鼠标的消息都将导致弹出窗口的消失。 然而WINDOWS API接口中没有现成的函数来实现此项功能,即使是最新版的 VISUAL C++ MFC也没有提供现成的类和函数来实现带阴影的此类窗口。为此,笔者基于面向对象的程序设计思想,从CWnd派生一个新类来实现这个功能,并且将该类窗口的所有函数完全封装在一起,使用就像调用“ MessageBox()”函数显示信息一样简单。

二.实现方法的几个关键部分说明如下 ,要解决怎样画非用户区的问题:当WINDOWS需要创建一个窗口时,它发送两个消息:WM_NCPAINT和 WM_PAINT到应用程序消息队列。WM_NCPAINT用于重画窗口的非用户区,如标题,边框和滚动杆,本程序正是响应WM_NCPAINT消息来重画带阴影的弹出窗口的边框;画客户区很简单,只需响应WM_PAINT消息处理字符的显示即可.2.如何动态调整弹出窗口的尺寸:大家知道,在一个矩形内显示文本串时,常用函数DrawText(HDC hDC,LPTSTR lpszText,int cbCount,RECT FAR* lpRect,UINT fuFormat).但是,此时我们的带阴影的弹出窗口并为建立.当然不能利用它来显示.然而,我们注意到上述函数中的最后一个参数FuFormat, 它是文字格式的组合,其中有一个鲜为人知的参数 DT_CALCRECT, 使用这个参数,字符串不显示,但它根据当前字体测量待显示串的高度, 本程序正是根据这个参数来确定弹出窗口的大小,并以此建立一个随字符串大小而变化的窗口,下面给出其实现该功能的片断: void CShadowWnd::ShowText(CString sText) dc.CreateDC("DISPLAY",NULL,NULL,NULL); //创建一个显示设备描述表 dc.SelectObject(GetStockObject(SYSTEM_FONT)); //选择字体到设备描述表 CRect rect(0,0,MAXWIDTH,0);// 

//获得待显示的字符串 sText 的实际高度和宽度,并将其存入矩形rect中   

  dc.DrawText(sText,rect,DT_WORDBREAK|DT_CENTER|DT_CALCRECT|DT_NOPREFIX);

3.怎样获取对系统的控制权:

   在带阴影的弹出窗口显示之后,怎样获取对系统的控制权,使得当用户按下键盘任意键或鼠标时都将使带阴影的弹出窗口消失,这里采取的方法是,当弹出窗口创建和显示之后,立即进入一个消息循环,从应用程序队列中获取所有消息,并判断是否为鼠标消息或键盘消息,如是,则摧毁窗口结束,并将控制权归还给调用程序.实现片断如下:
//进入消息循环,获取全部消息,控制整个系统
 1      MSG Msg;
 2      BOOL bDone;
 3      SetCapture();
 4      bDone  =  FALSE;
 5       while ( ! bDone)
 6      {
 7           if (PeekMessage( & Msg,NULL, 0 , 0 ,PM_REMOVE))
 8               if (Msg.message  ==  WM_KEYDOWN  ||  Msg.message  ==  WM_SYSKEYDOWN ||
 9                  Msg.message  ==  WM_LBUTTONDOWN  ||  Msg.message  ==  WM_RBUTTONDOWN)
10                  bDone  =  TRUE;
11               else
12              {
13                  TranslateMessage( & Msg);
14                  DispatchMessage( & Msg);
15              }
16      }
17  ReleaseCapture();
      DestroyWindow();

. 带阴影的类 CShadowWnd 类的头文件及其实现文件的全部细节

 1  #pragma once
 2 
 3 
 4  //  CShadowWnd
 5 
 6  class  CShadowWnd :  public  CWnd
 7  {
 8      DECLARE_DYNAMIC(CShadowWnd)
 9 
10  public :
11      CShadowWnd();
12       virtual   ~ CShadowWnd();
13 
14  protected :
15      DECLARE_MESSAGE_MAP()
16 
17  public :
18       virtual  BOOL Create( const  RECT &  rect, CWnd *  pParentWnd);
19      CString m_sShowText;
20       void  ShowReadOnlyText(CString sText);
21      CBrush m_bmpBrush;
22  protected :
23      afx_msg  void  OnNcPaint();
24      afx_msg  void  OnPaint();
25      afx_msg  int  OnCreate(LPCREATESTRUCT lpCreateStruct);
26 
27  };
28 

// cpp
  1  //  ShadowWnd.cpp : 实现文件
  2  //
  3 
  4  #include  " stdafx.h "
  5  #include  " MFCApp.h "
  6  #include  " ShadowWnd.h "
  7 
  8  // 阴影位图数组 
  9  static   int  aPattern[] = { 0xAA , 0x55 , 0xAA , 0x55 , 0xAA , 0x55 , 0xAA , 0x55 };
 10  #define  SPOPUP_SHADOWWIDTH 10     // 阴影宽度 
 11  #define  SPOPUP_SHADOWHEIGHT 13     // 阴影高度 
 12  #define     MAXWIDTH    400             // 显示字符矩形的最大宽度 
 13 
 14 
 15  IMPLEMENT_DYNAMIC(CShadowWnd, CWnd)
 16 
 17  CShadowWnd::CShadowWnd()
 18  {
 19      CBitmap bmp;
 20      bmp.CreateBitmap( 8 , 8 , 1 , 1 ,( void * )aPattern);     // 创建一个阴影位图 
 21      m_bmpBrush.CreatePatternBrush( & bmp);         // 创建一把阴影刷 
 22  }
 23 
 24  CShadowWnd:: ~ CShadowWnd()
 25  {
 26  }
 27 
 28 
 29  BEGIN_MESSAGE_MAP(CShadowWnd, CWnd)
 30      ON_WM_NCPAINT()
 31      ON_WM_PAINT()
 32      ON_WM_CREATE()
 33  END_MESSAGE_MAP()
 34 
 35  BOOL CShadowWnd::Create( const  RECT &  rect, CWnd *  pParentWnd)
 36  {
 37      LPCTSTR pClassName  =  AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
 38       return  CWnd::CreateEx(WS_EX_STATICEDGE,pClassName,L " Shadow window " ,WS_POPUP,
 39          rect.left,rect.top,rect.right,rect.bottom,
 40          pParentWnd -> GetSafeHwnd(), 0 ,NULL);
 41  }
 42  void  CShadowWnd::OnNcPaint()
 43  {
 44      CWindowDC dc( this );
 45      CRect rc;
 46      GetWindowRect( & rc);
 47      rc.right  -=  rc.left;
 48      rc.bottom  -=  rc.top;
 49      rc.top  =   0 ;
 50      rc.left  =   0 ;
 51      m_bmpBrush.UnrealizeObject();
 52      CBrush  * OldBrush  =  dc.SelectObject( & m_bmpBrush);
 53       // 画底部阴影 
 54      dc.PatBlt(rc.left + SPOPUP_SHADOWWIDTH,rc.bottom - SPOPUP_SHADOWHEIGHT,
 55          rc.right - SPOPUP_SHADOWWIDTH,SPOPUP_SHADOWHEIGHT,PATCOPY);
 56       // 画右边阴影 
 57      dc.PatBlt(rc.right - SPOPUP_SHADOWWIDTH,rc.top + SPOPUP_SHADOWHEIGHT,
 58          SPOPUP_SHADOWWIDTH,rc.bottom,PATCOPY);
 59      dc.SelectObject(OldBrush);
 60      CBrush  * pBrush  =  CBrush::FromHandle(GetSysColorBrush(COLOR_WINDOWFRAME));
 61      rc.right  -=  SPOPUP_SHADOWWIDTH;
 62      rc.bottom  -=  SPOPUP_SHADOWHEIGHT;
 63      dc.FrameRect(rc,pBrush);     // 画边框 
 64  }
 65 
 66  void  CShadowWnd::OnPaint()
 67  {
 68      CPaintDC dc( this );  //  device context for painting
 69      CRect rect;
 70      GetClientRect( & rect);
 71      rect.left  +=   5 ;
 72      rect.top  +=   5 ;
 73      rect.right  -=  SPOPUP_SHADOWWIDTH;
 74      rect.bottom  -=  SPOPUP_SHADOWHEIGHT;
 75      dc.SetTextColor(RGB( 0 , 0 , 255 ));
 76      dc.DrawText(m_sShowText,rect,DT_WORDBREAK | DT_NOPREFIX);
 77  }
 78 
 79  void  CShadowWnd::ShowReadOnlyText(CString sText)
 80  {
 81      m_sShowText  =  sText;     // 存入显示字符串 
 82      CDC dc;
 83      dc.CreateDC(L " DISPLAY " ,NULL,NULL,NULL);     // 创建一个显示设备描述表 
 84      dc.SelectObject(GetStockObject(SYSTEM_FONT));     // 选择字体到设备描述表 
 85      CRect rect( 0 , 0 ,MAXWIDTH, 0 );
 86       // 获得待显示的字符串 sText 的实际高度和宽度 
 87      dc.DrawText(sText,rect,DT_WORDBREAK | DT_CENTER | DT_CALCRECT | DT_NOPREFIX);
 88       // 为矩形留些余量 
 89      rect.right  +=   3 * SPOPUP_SHADOWWIDTH;
 90      rect.bottom  +=   3 * SPOPUP_SHADOWHEIGHT;
 91       this -> Create(rect, 0 );     // 创建窗口 
 92       this -> ShowWindow(SW_SHOW);
 93       this -> UpdateWindow();     // 立刻更新窗口 
 94       // 进入消息循环,获取全部消息,控制整个系统 
 95      MSG Msg;
 96      BOOL bDone;
 97      SetCapture();
 98      bDone  =  FALSE;
 99       while ( ! bDone)
100      {
101           if (PeekMessage( & Msg,NULL, 0 , 0 ,PM_REMOVE))
102               if (Msg.message  ==  WM_KEYDOWN  ||  Msg.message  ==  WM_SYSKEYDOWN ||
103                  Msg.message  ==  WM_LBUTTONDOWN  ||  Msg.message  ==  WM_RBUTTONDOWN)
104                  bDone  =  TRUE;
105               else
106              {
107                  TranslateMessage( & Msg);
108                  DispatchMessage( & Msg);
109              }
110      }
111      ReleaseCapture();
112      DestroyWindow();
113  }
114 
115  int  CShadowWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
116  {
117       if  (CWnd::OnCreate(lpCreateStruct)  ==   - 1 )
118           return   - 1 ;
119      CenterWindow();
120       return   0 ;
121  }
122 

四.使用方法:

1.   将该类增加到一个项目文件中

2. 在你欲使用函数的类(一般为视类或框架窗口类)中增加一个成员变量(如:CShadowWnd m_ShadowWnd),当需要使用带阴影的弹出窗口显示信息时,调用成员函数(如: m_ShadowWnd.ShowReadOnlyText(String sText)即可,无须考虑其实现细节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值