VC只用GDI实现位图展现简单特效
2014-09-03 19:44
381 查看
展示截图(略大,4.24M):
Demo下载(需要1积分):http://download.csdn.net/detail/joneeky/7860555
这些把位图加载到内存DC上的代码需要重复使用,于是定义成宏:
百叶窗就是把位图分块同步显示,原理比较简单。
拉直其实和百叶窗相差不了多少,也是分块同步显示,但是每一块是慢慢变大的。
由小变大主要是要保存图像比例和算位图从在哪个坐标显示,图像大小发生变化,坐标随之变化。可以先确定图像的宽,然后 长=宽*(高/2);x坐标=位图实际的宽/2-当前的宽/2,y坐标=位图实际的高/2-当前的高/2。
旋转变大比较复杂,在上网找到可以完成位图按任意弧度旋转的代码改了一下,使其可以指定显示的大小:
最后一个参数的颜色值,指定图像旋转后空出来的位置填充的颜色
只要是要控制当位图变到最大时旋转角度是0度,也就是说当变到最大时就不能再大了,但是如果角度不是0度也还是要转到0度去。
还有就是我使用了双缓冲,怎么还闪烁得这么厉害我也不清楚了。
Demo下载(需要1积分):http://download.csdn.net/detail/joneeky/7860555
这些把位图加载到内存DC上的代码需要重复使用,于是定义成宏:
#define READY_CODE \ CGditestDlg *pMainDlg = (CGditestDlg *)pParam; \ CDC *pDC = pMainDlg->GetDC(); \ CBitmap bmp; \ if (1 == pMainDlg->m_counter) \ { \ bmp.LoadBitmap(IDB_BITMAP1); \ pMainDlg->m_counter = 2; \ } \ else if (2 == pMainDlg->m_counter) \ { \ bmp.LoadBitmap(IDB_BITMAP2); \ pMainDlg->m_counter = 3; \ } \ else \ { \ bmp.LoadBitmap(IDB_BITMAP3); \ pMainDlg->m_counter = 1; \ } \ CDC dcMem; \ dcMem.CreateCompatibleDC(pDC); \ dcMem.SelectObject(&bmp); \ BITMAP bm; \ bmp.GetBitmap(&bm); \ pMainDlg->Invalidate(); \ EnumChildWindows(pMainDlg->GetSafeHwnd(), \ EnumChildProc, 0L); #define CLEAN_CODE \ dcMem.DeleteDC(); \ bmp.DeleteObject(); \ EnumChildWindows( \ pMainDlg->GetSafeHwnd(),\ EnumChildProc, 1L); \ #define PI 3.14 //弧度 = 2π * 角度 / 360 #define RADIAN(degree) ((float)((2 * PI * degree) / 360))
/*从上飞入*/ UINT CGditestDlg::FlyIntoFromTop(LPVOID pParam) { READY_CODE for (int ySrc = bm.bmHeight; ySrc >= 0; ySrc -= 10) { pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem, 0, ySrc, SRCCOPY); Sleep(1); } CLEAN_CODE return 0; }
/*从左飞入*/ UINT CGditestDlg::FlyIntoFromLeft(LPVOID pParam) { READY_CODE for (int xSrc = bm.bmWidth; xSrc >= 0; xSrc -= 10) { pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem, xSrc, 0, SRCCOPY); Sleep(1); } CLEAN_CODE return 0; }
/*从上展开*/ UINT CGditestDlg::UnfoldFromTop(LPVOID pParam) { READY_CODE for (int htDes = 0; htDes <= bm.bmHeight; htDes += 10) { pDC->BitBlt(0, 0, bm.bmWidth, htDes, &dcMem, 0, 0, SRCCOPY); Sleep(1); } CLEAN_CODE return 0; }
/*从左展开*/ UINT CGditestDlg::UnfoldFromLeft(LPVOID pParam) { READY_CODE for (int wtDes = 0; wtDes <= bm.bmWidth; wtDes += 10) { pDC->BitBlt(0, 0, wtDes, bm.bmHeight, &dcMem, 0, 0, SRCCOPY); Sleep(1); } CLEAN_CODE return 0; }
百叶窗就是把位图分块同步显示,原理比较简单。
/*水平百叶窗*/ UINT CGditestDlg::HorizontalWindow(LPVOID pParam) { READY_CODE int n = bm.bmHeight / 8; for (int htDes = 0; htDes <= n; htDes += 1) { for (int i = 0; i < 8; i++) { pDC->BitBlt(0, n * i, bm.bmWidth, htDes, &dcMem, 0, n * i, SRCCOPY); } Sleep(10); } CLEAN_CODE return 0; }
/*垂直百叶窗*/ UINT CGditestDlg::VerticalWindow(LPVOID pParam) { READY_CODE int n = bm.bmWidth / 8; for (int wtDes = 0; wtDes <= n; wtDes += 1) { for (int i = 0; i < 8; i++) { pDC->BitBlt(n * i, 0, wtDes, bm.bmHeight, &dcMem, n * i, 0, SRCCOPY); } Sleep(10); } CLEAN_CODE return 0; }
拉直其实和百叶窗相差不了多少,也是分块同步显示,但是每一块是慢慢变大的。
/*往下拉直*/ UINT CGditestDlg::StraightenToBottom(LPVOID pParam) { READY_CODE int n = bm.bmHeight / 8; for (int htDes = 0; htDes <= n; htDes += 1) { for (int i = 0; i < 8; i++) { pDC->BitBlt(0, htDes * i, bm.bmWidth, htDes, &dcMem, 0, n * i, SRCCOPY); } Sleep(10); } CLEAN_CODE return 0; }
/*往右拉直*/ UINT CGditestDlg::StraightenToRight(LPVOID pParam) { READY_CODE int n = bm.bmWidth / 8; for (int wtDes = 0; wtDes <= n; wtDes += 1) { for (int i = 0; i < 8; i++) { pDC->BitBlt(wtDes * i, 0, wtDes, bm.bmHeight, &dcMem, n * i, 0, SRCCOPY); } Sleep(10); } CLEAN_CODE return 0; }
由小变大主要是要保存图像比例和算位图从在哪个坐标显示,图像大小发生变化,坐标随之变化。可以先确定图像的宽,然后 长=宽*(高/2);x坐标=位图实际的宽/2-当前的宽/2,y坐标=位图实际的高/2-当前的高/2。
/*由小变大*/ UINT CGditestDlg::SmallToLarge(LPVOID pParam) { READY_CODE float x, y, w, h; float base = 0; pDC->SetStretchBltMode(HALFTONE); while ((int)(base += 10) <= bm.bmWidth) { w = base; h = base * ((float)bm.bmHeight / (float)bm.bmWidth); x = (float)bm.bmWidth / 2 - w / 2; y = (float)bm.bmHeight / 2 - h / 2; pDC->StretchBlt((int)x, (int)y, (int)w, (int)h, &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); Sleep(10); } CLEAN_CODE return 0; }
旋转变大比较复杂,在上网找到可以完成位图按任意弧度旋转的代码改了一下,使其可以指定显示的大小:
最后一个参数的颜色值,指定图像旋转后空出来的位置填充的颜色
HBITMAP GetRotatedBitmap(HBITMAP hBitmap, float radians, int width, int height, COLORREF clrBack) { // Create a memory DC compatible with the display CDC sourceDC, destDC; sourceDC.CreateCompatibleDC( NULL ); destDC.CreateCompatibleDC( NULL ); // Get logical coordinates BITMAP bm, bmOld; ::GetObject( hBitmap, sizeof( bm ), &bm ); bmOld = bm; bm.bmWidth = width; bm.bmHeight = height; float cosine = (float)cos(radians); float sine = (float)sin(radians); // Compute dimensions of the resulting bitmap // First get the coordinates of the 3 corners other than origin int x1 = (int)(bm.bmHeight * sine); int y1 = (int)(bm.bmHeight * cosine); int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine); int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine); int x3 = (int)(bm.bmWidth * cosine); int y3 = (int)(-bm.bmWidth * sine); int minx = min(0,min(x1, min(x2,x3))); int miny = min(0,min(y1, min(y2,y3))); int maxx = max(0,max(x1, max(x2,x3))); int maxy = max(0,max(y1, max(y2,y3))); int w = maxx - minx; int h = maxy - miny; // Create a bitmap to hold the result HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h); HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap ); HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult ); // Draw the background color before we change mapping mode HBRUSH hbrBack = CreateSolidBrush( clrBack ); HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack ); destDC.PatBlt( 0, 0, w, h, PATCOPY ); ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) ); // We will use world transform to rotate the bitmap SetGraphicsMode(destDC.m_hDC, GM_ADVANCED); XFORM xform; xform.eM11 = cosine; xform.eM12 = -sine; xform.eM21 = sine; xform.eM22 = cosine; xform.eDx = (float)-minx; xform.eDy = (float)-miny; SetWorldTransform( destDC.m_hDC, &xform ); // Now do the actual rotating - a pixel at a time // destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY ); destDC.SetStretchBltMode(HALFTONE); destDC.StretchBlt(0, 0, bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, bmOld.bmWidth, bmOld.bmHeight, SRCCOPY); // Restore DCs ::SelectObject( sourceDC.m_hDC, hbmOldSource ); ::SelectObject( destDC.m_hDC, hbmOldDest ); return hbmResult; }
只要是要控制当位图变到最大时旋转角度是0度,也就是说当变到最大时就不能再大了,但是如果角度不是0度也还是要转到0度去。
还有就是我使用了双缓冲,怎么还闪烁得这么厉害我也不清楚了。
/*旋转变大*/ UINT CGditestDlg::LargerWithSpin(LPVOID pParam) { // READY_CODE CGditestDlg *pMainDlg = (CGditestDlg *)pParam; CDC *pDC = pMainDlg->GetDC(); pMainDlg->Invalidate(); EnumChildWindows(pMainDlg->GetSafeHwnd(), EnumChildProc, 0L); pDC->SetStretchBltMode(HALFTONE); CBitmap bmp; if (1 == pMainDlg->m_counter) { bmp.LoadBitmap(IDB_BITMAP1); pMainDlg->m_counter = 2; } else if (2 == pMainDlg->m_counter) { bmp.LoadBitmap(IDB_BITMAP2); pMainDlg->m_counter = 3; } else { bmp.LoadBitmap(IDB_BITMAP3); pMainDlg->m_counter = 1; } HBITMAP hBmp; CDC dcMem; CBitmap *pbmpRotated; BITMAP bm; int degree = 0; float width, height; float base = 0; long oldWidth, oldHeight; float x, y; int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0; dcMem.CreateCompatibleDC(pDC); bmp.GetBitmap(&bm); oldWidth = bm.bmWidth; oldHeight = bm.bmHeight; CRect rcWnd; pMainDlg->GetWindowRect(&rcWnd); CBitmap bmpBkgd; CDC dcBkgd; dcBkgd.CreateCompatibleDC(pDC); bmpBkgd.CreateCompatibleBitmap(pDC, rcWnd.Width() + 200, rcWnd.Height() + 200); dcBkgd.SelectObject(&bmpBkgd); dcBkgd.FillSolidRect(0, 0, rcWnd.Width() + 200, rcWnd.Height() + 200, RGB(255, 174 ,201)); while (1) { if (base <= oldWidth) { base += 15; } if (base > oldWidth && degree == 0) { break; } width = base; height = base * ((float)oldHeight / (float)oldWidth); hBmp = GetRotatedBitmap((HBITMAP)bmp.GetSafeHandle(), RADIAN(degree), (int)width, (int)height, RGB(255, 174 ,201)); pbmpRotated = CBitmap::FromHandle(hBmp); dcMem.SelectObject(pbmpRotated); pbmpRotated->GetBitmap(&bm); x = (float)oldWidth / 2 - (float)bm.bmWidth / 2; y = (float)oldHeight / 2 - (float)bm.bmHeight / 2; pDC->BitBlt(lastX, lastY, lastWidth, lastHeight, &dcBkgd, 0, 0, SRCCOPY); pDC->BitBlt((int)x, (int)y, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, SRCCOPY); lastX = (int)x; lastY = (int)y; lastWidth = bm.bmWidth; lastHeight = bm.bmHeight; pbmpRotated->DeleteObject(); degree = (degree += 15) > 360 ? 0 : degree; Sleep(1); } dcMem.DeleteDC(); dcBkgd.DeleteDC(); bmpBkgd.DeleteObject(); EnumChildWindows(pMainDlg->GetSafeHwnd(), EnumChildProc, 1L); // CLEAN_CODE return 0; }
相关文章推荐
- VC只用GDI实现位图展现简单特效
- GDI实现图像的简单显示特效
- VC中使用GDI函数实现位图的透明
- VC中使用GDI函数实现位图的透明
- VC中使用GDI函数实现位图的透明
- 利用VC++实现WIN95/NT下位图淡入淡出的二种技巧
- 双缓冲技术及其在VC的GDI环境下的实现
- VC中实现带有背景位图的树型控件
- 简单SNMP管理程序的VC++代码实例实现
- vc实现BMP位图文件结构及平滑缩放
- 简单SNMP管理程序的VC++代码实例实现
- 利用VC++实现WIN95/NT下位图淡入淡出的二种技巧
- JSP只用Hashtable和session实现购物车功能的简单实例
- 求助:在vc中gdi编程中如何实现图形放缩和平移?
- VC 中实现 XP 风格的控件,简单实用的方法包你满意!
- java/vc单点登录的简单实现-Java基础-Java-编程开发
- 一个简单的Convert类的实现(VC++)
- 一个简单的windows位图文件类的实现
- 简单SNMP管理程序的VC++代码实例实现
- VC实现BMP位图文件结构及平滑缩放