VC只用GDI实现位图展现简单特效

展示截图(略大,4.24M):


Demo下载(需要1积分):http://download.csdn.net/detail/joneeky/7860555


这些把位图加载到内存DC上的代码需要重复使用,于是定义成宏:

  1. #define READY_CODE                              \  
  2. CGditestDlg *pMainDlg = (CGditestDlg *)pParam;  \  
  3. CDC *pDC = pMainDlg->GetDC();                    \  
  4. CBitmap bmp;                                    \  
  5. if (1 == pMainDlg->m_counter)                    \  
  6. {                                               \  
  7.     bmp.LoadBitmap(IDB_BITMAP1);                \  
  8.     pMainDlg->m_counter = 2;                 \  
  9. }                                               \  
  10. else if (2 == pMainDlg->m_counter)               \  
  11. {                                               \  
  12.     bmp.LoadBitmap(IDB_BITMAP2);                \  
  13.     pMainDlg->m_counter = 3;                 \  
  14. }                                               \  
  15. else                                            \  
  16. {                                               \  
  17.     bmp.LoadBitmap(IDB_BITMAP3);                \  
  18.     pMainDlg->m_counter = 1;                 \  
  19. }                                               \  
  20. CDC dcMem;                                      \  
  21. dcMem.CreateCompatibleDC(pDC);                  \  
  22. dcMem.SelectObject(&bmp);                       \  
  23. BITMAP bm;                                      \  
  24. bmp.GetBitmap(&bm);                             \  
  25. pMainDlg->Invalidate();                          \  
  26. EnumChildWindows(pMainDlg->GetSafeHwnd(),        \  
  27.     EnumChildProc, 0L);  
  28.   
  29. #define CLEAN_CODE          \  
  30. dcMem.DeleteDC();           \  
  31. bmp.DeleteObject();         \  
  32. EnumChildWindows(           \  
  33.     pMainDlg->GetSafeHwnd(),\  
  34.     EnumChildProc, 1L);     \  
  35.   
  36. #define PI  3.14  
  37.   
  38. //弧度 = 2π * 角度 / 360  
  39. #define RADIAN(degree)  ((float)((2 * PI * degree) / 360))  

  1. /*从上飞入*/  
  2. UINT CGditestDlg::FlyIntoFromTop(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     for (int ySrc = bm.bmHeight; ySrc >= 0; ySrc -= 10)  
  6.     {  
  7.         pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem, 0, ySrc, SRCCOPY);  
  8.         Sleep(1);  
  9.     }  
  10.     CLEAN_CODE  
  11.     return 0;  
  12. }  

  1. /*从左飞入*/  
  2. UINT CGditestDlg::FlyIntoFromLeft(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     for (int xSrc = bm.bmWidth; xSrc >= 0; xSrc -= 10)  
  6.     {  
  7.         pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem, xSrc, 0, SRCCOPY);  
  8.         Sleep(1);  
  9.     }  
  10.     CLEAN_CODE  
  11.     return 0;  
  12. }  

  1. /*从上展开*/  
  2. UINT CGditestDlg::UnfoldFromTop(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     for (int htDes = 0; htDes <= bm.bmHeight; htDes += 10)  
  6.     {  
  7.         pDC->BitBlt(0, 0, bm.bmWidth, htDes, &dcMem, 0, 0, SRCCOPY);  
  8.         Sleep(1);  
  9.     }  
  10.     CLEAN_CODE  
  11.     return 0;  
  12. }  

  1. /*从左展开*/  
  2. UINT CGditestDlg::UnfoldFromLeft(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     for (int wtDes = 0; wtDes <= bm.bmWidth; wtDes += 10)  
  6.     {  
  7.         pDC->BitBlt(0, 0, wtDes, bm.bmHeight, &dcMem, 0, 0, SRCCOPY);  
  8.         Sleep(1);  
  9.     }  
  10.     CLEAN_CODE  
  11.     return 0;  
  12. }  


百叶窗就是把位图分块同步显示,原理比较简单。
  1. /*水平百叶窗*/  
  2. UINT CGditestDlg::HorizontalWindow(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     int n = bm.bmHeight / 8;  
  6.     for (int htDes = 0; htDes <= n; htDes += 1)  
  7.     {  
  8.         for (int i = 0; i < 8; i++)  
  9.         {  
  10.             pDC->BitBlt(0, n * i, bm.bmWidth, htDes, &dcMem, 0, n * i, SRCCOPY);  
  11.         }  
  12.         Sleep(10);  
  13.     }  
  14.     CLEAN_CODE  
  15.     return 0;  
  16. }  

  1. /*垂直百叶窗*/  
  2. UINT CGditestDlg::VerticalWindow(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     int n = bm.bmWidth / 8;  
  6.     for (int wtDes = 0; wtDes <= n; wtDes += 1)  
  7.     {  
  8.         for (int i = 0; i < 8; i++)  
  9.         {  
  10.             pDC->BitBlt(n * i, 0, wtDes, bm.bmHeight, &dcMem, n * i, 0, SRCCOPY);  
  11.         }  
  12.         Sleep(10);  
  13.     }  
  14.     CLEAN_CODE  
  15.     return 0;  
  16. }  


拉直其实和百叶窗相差不了多少,也是分块同步显示,但是每一块是慢慢变大的。


  1. /*往下拉直*/  
  2. UINT CGditestDlg::StraightenToBottom(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     int n = bm.bmHeight / 8;  
  6.     for (int htDes = 0; htDes <= n; htDes += 1)  
  7.     {  
  8.         for (int i = 0; i < 8; i++)  
  9.         {  
  10.             pDC->BitBlt(0, htDes * i, bm.bmWidth, htDes, &dcMem, 0, n * i, SRCCOPY);  
  11.         }  
  12.         Sleep(10);  
  13.     }  
  14.     CLEAN_CODE  
  15.     return 0;  
  16. }  

  1. /*往右拉直*/  
  2. UINT CGditestDlg::StraightenToRight(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     int n = bm.bmWidth / 8;  
  6.     for (int wtDes = 0; wtDes <= n; wtDes += 1)  
  7.     {  
  8.         for (int i = 0; i < 8; i++)  
  9.         {  
  10.             pDC->BitBlt(wtDes * i, 0, wtDes, bm.bmHeight, &dcMem, n * i, 0, SRCCOPY);  
  11.         }  
  12.         Sleep(10);  
  13.     }  
  14.     CLEAN_CODE  
  15.     return 0;  
  16. }  


由小变大主要是要保存图像比例和算位图从在哪个坐标显示,图像大小发生变化,坐标随之变化。可以先确定图像的宽,然后 长=宽*(高/2);x坐标=位图实际的宽/2-当前的宽/2,y坐标=位图实际的高/2-当前的高/2。


  1. /*由小变大*/  
  2. UINT CGditestDlg::SmallToLarge(LPVOID pParam)  
  3. {  
  4.     READY_CODE  
  5.     float x, y, w, h;  
  6.     float base = 0;  
  7.     pDC->SetStretchBltMode(HALFTONE);  
  8.     while ((int)(base += 10) <= bm.bmWidth)  
  9.     {  
  10.         w = base;  
  11.         h = base * ((float)bm.bmHeight / (float)bm.bmWidth);  
  12.         x = (float)bm.bmWidth / 2 - w / 2;  
  13.         y = (float)bm.bmHeight / 2 - h / 2;  
  14.         pDC->StretchBlt((int)x, (int)y, (int)w, (int)h, &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);  
  15.         Sleep(10);  
  16.     }  
  17.     CLEAN_CODE  
  18.     return 0;  
  19. }  

旋转变大比较复杂,在上网找到可以完成位图按任意弧度旋转的代码改了一下,使其可以指定显示的大小:

最后一个参数的颜色值,指定图像旋转后空出来的位置填充的颜色

  1. HBITMAP GetRotatedBitmap(HBITMAP hBitmap, float radians, int width, int height, COLORREF clrBack)    
  2. {    
  3.     // Create a memory DC compatible with the display    
  4.     CDC sourceDC, destDC;    
  5.     sourceDC.CreateCompatibleDC( NULL );    
  6.     destDC.CreateCompatibleDC( NULL );    
  7.       
  8.     // Get logical coordinates    
  9.     BITMAP bm, bmOld;    
  10.     ::GetObject( hBitmap, sizeof( bm ), &bm );    
  11.     bmOld = bm;  
  12.     bm.bmWidth = width;  
  13.     bm.bmHeight = height;  
  14.       
  15.     float cosine = (float)cos(radians);    
  16.     float sine = (float)sin(radians);    
  17.       
  18.     // Compute dimensions of the resulting bitmap    
  19.     // First get the coordinates of the 3 corners other than origin    
  20.     int x1 = (int)(bm.bmHeight * sine);    
  21.     int y1 = (int)(bm.bmHeight * cosine);    
  22.     int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);    
  23.     int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);    
  24.     int x3 = (int)(bm.bmWidth * cosine);    
  25.     int y3 = (int)(-bm.bmWidth * sine);    
  26.       
  27.     int minx = min(0,min(x1, min(x2,x3)));    
  28.     int miny = min(0,min(y1, min(y2,y3)));    
  29.     int maxx = max(0,max(x1, max(x2,x3)));    
  30.     int maxy = max(0,max(y1, max(y2,y3)));    
  31.       
  32.     int w = maxx - minx;    
  33.     int h = maxy - miny;    
  34.       
  35.     // Create a bitmap to hold the result    
  36.     HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);    
  37.       
  38.     HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );    
  39.     HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );    
  40.       
  41.     // Draw the background color before we change mapping mode    
  42.     HBRUSH hbrBack = CreateSolidBrush( clrBack );    
  43.     HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );    
  44.     destDC.PatBlt( 0, 0, w, h, PATCOPY );    
  45.     ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );    
  46.       
  47.     // We will use world transform to rotate the bitmap    
  48.     SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);    
  49.     XFORM xform;    
  50.     xform.eM11 = cosine;    
  51.     xform.eM12 = -sine;    
  52.     xform.eM21 = sine;    
  53.     xform.eM22 = cosine;    
  54.     xform.eDx = (float)-minx;    
  55.     xform.eDy = (float)-miny;    
  56.       
  57.     SetWorldTransform( destDC.m_hDC, &xform );    
  58.       
  59.     // Now do the actual rotating - a pixel at a time    
  60. //  destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );    
  61.     destDC.SetStretchBltMode(HALFTONE);  
  62.     destDC.StretchBlt(0, 0, bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, bmOld.bmWidth, bmOld.bmHeight, SRCCOPY);  
  63.       
  64.     // Restore DCs    
  65.     ::SelectObject( sourceDC.m_hDC, hbmOldSource );    
  66.     ::SelectObject( destDC.m_hDC, hbmOldDest );    
  67.       
  68.     return hbmResult;    
  69. }  


只要是要控制当位图变到最大时旋转角度是0度,也就是说当变到最大时就不能再大了,但是如果角度不是0度也还是要转到0度去。

还有就是我使用了双缓冲,怎么还闪烁得这么厉害我也不清楚了。


  1. /*旋转变大*/  
  2. UINT CGditestDlg::LargerWithSpin(LPVOID pParam)  
  3. {  
  4. //  READY_CODE  
  5.     CGditestDlg *pMainDlg = (CGditestDlg *)pParam;  
  6.     CDC *pDC = pMainDlg->GetDC();  
  7.     pMainDlg->Invalidate();  
  8.     EnumChildWindows(pMainDlg->GetSafeHwnd(), EnumChildProc, 0L);  
  9.     pDC->SetStretchBltMode(HALFTONE);  
  10.     CBitmap bmp;  
  11.     if (1 == pMainDlg->m_counter)  
  12.     {  
  13.         bmp.LoadBitmap(IDB_BITMAP1);  
  14.         pMainDlg->m_counter = 2;  
  15.     }  
  16.     else if (2 == pMainDlg->m_counter)  
  17.     {  
  18.         bmp.LoadBitmap(IDB_BITMAP2);  
  19.         pMainDlg->m_counter = 3;  
  20.     }  
  21.     else  
  22.     {  
  23.         bmp.LoadBitmap(IDB_BITMAP3);  
  24.         pMainDlg->m_counter = 1;  
  25.     }  
  26.     HBITMAP hBmp;  
  27.     CDC dcMem;  
  28.     CBitmap *pbmpRotated;  
  29.     BITMAP bm;  
  30.     int degree = 0;  
  31.     float width, height;  
  32.     float base = 0;  
  33.     long oldWidth, oldHeight;  
  34.     float x, y;  
  35.     int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0;  
  36.     dcMem.CreateCompatibleDC(pDC);  
  37.     bmp.GetBitmap(&bm);  
  38.     oldWidth = bm.bmWidth;  
  39.     oldHeight = bm.bmHeight;  
  40.     CRect rcWnd;  
  41.     pMainDlg->GetWindowRect(&rcWnd);  
  42.     CBitmap bmpBkgd;  
  43.     CDC dcBkgd;  
  44.     dcBkgd.CreateCompatibleDC(pDC);  
  45.     bmpBkgd.CreateCompatibleBitmap(pDC, rcWnd.Width() + 200, rcWnd.Height() + 200);  
  46.     dcBkgd.SelectObject(&bmpBkgd);  
  47.     dcBkgd.FillSolidRect(0, 0, rcWnd.Width() + 200, rcWnd.Height() + 200, RGB(255, 174 ,201));  
  48.     while (1)  
  49.     {  
  50.         if (base <= oldWidth)  
  51.         {  
  52.             base += 15;  
  53.         }  
  54.         if (base > oldWidth && degree == 0)  
  55.         {  
  56.             break;  
  57.         }  
  58.         width = base;  
  59.         height = base * ((float)oldHeight / (float)oldWidth);  
  60.         hBmp = GetRotatedBitmap((HBITMAP)bmp.GetSafeHandle(), RADIAN(degree), (int)width, (int)height, RGB(255, 174 ,201));  
  61.         pbmpRotated = CBitmap::FromHandle(hBmp);  
  62.         dcMem.SelectObject(pbmpRotated);  
  63.         pbmpRotated->GetBitmap(&bm);  
  64.         x = (float)oldWidth / 2 - (float)bm.bmWidth / 2;  
  65.         y = (float)oldHeight / 2 - (float)bm.bmHeight / 2;  
  66.         pDC->BitBlt(lastX, lastY, lastWidth, lastHeight, &dcBkgd, 0, 0, SRCCOPY);  
  67.         pDC->BitBlt((int)x, (int)y, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, SRCCOPY);  
  68.         lastX = (int)x;  
  69.         lastY = (int)y;  
  70.         lastWidth = bm.bmWidth;  
  71.         lastHeight = bm.bmHeight;  
  72.         pbmpRotated->DeleteObject();  
  73.         degree = (degree += 15) > 360 ? 0 : degree;  
  74.         Sleep(1);  
  75.     }  
  76.     dcMem.DeleteDC();  
  77.     dcBkgd.DeleteDC();  
  78.     bmpBkgd.DeleteObject();  
  79.     EnumChildWindows(pMainDlg->GetSafeHwnd(), EnumChildProc, 1L);  
  80.   
  81. //  CLEAN_CODE  
  82.     return 0;  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值