澳门新葡亰网址下载VC++6.0中关于贴图和解决屏幕闪烁的问题。

by admin on 2020年1月27日

基于VC++6.0,且使用MFC框架。VC++6.0集成了GDI,所以能导入的图片的格
式只能是bmp的,如果想直接导入其它格式图片,请参阅GDI+方面的书籍。
    首先建立一个单文档的工程test,这就不必多说了吧:-) ,
    
    下面开始贴图:
  1.导入图片(假设图片为map.bmp).
       在test resources那里单击右键,选择Insert…,在弹出的Insert
Resource
      
对话框左边选择Bitmap,然后点击右边的Import,打开文件map.bmp,这时候有可能弹出一
      
个对话框说一长串话,管它的呢,确定吧。然后看到Resources里面就多了一个Bitmap,
       它下面就有一张图片了,ID为IDB_BITMAP1,这个ID可以自己修改。
      
      以下工作的CTestView类的OnDraw函数中进行.
    2.创建位图对象,并与要显示的图片(此处为IDB_BITMAP1标识的图片)关联. 
      
       CBitmap bmp;
     bmp.LoadBitmap(IDB_BITMAP1);

在很多系统中出于美观的需要常常要设置背景图片。下面我介绍一种在客户区设置背景图片的简单方法。

位图操作和双缓冲机制

   3.创建兼容的DC,即内存DC.

 

位图操作
代码部分:
 CRect rect;
 GetClientRect(rect);
 pDC->SetMapMode(MM_ANISOTROPIC);
 pDC->SetWindowExt(rect.Width(), rect.Height());
 pDC->SetViewportExt(rect.Width(), -rect.Height());
 pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);

       CDC memDC;
       memDC.CreateCompatibleDC(pDC);
    
    4.将位图对象选入兼容DC.
  
       memDC.SelectObject(&bmp);  
    
    5.将兼容DC中的位图贴到窗口.
  
      pDC->BitBlt(x,y,width,height,&memDC,0,0,SRCCOPY);
      其中(x,y)表示图片的左上角在窗口中的坐标,
      idth,height分别表示图片的宽度和高度.
      
      这样贴图就完成了.  
  
  
 但是在许多游戏编程中会出现画面不停的闪烁的情况,这是由于游戏中的物体是
     
不停的运动的,那就要不断的贴图,但是贴图是需要一定的时间的,当贴图更不上的时候,那就会闪了

1 .将背景bmp 图片导入到工程,资源ID 这里假设为 IDB_BITMAP1

 CDC MemDC;
 CBitmap NewBitmap, *pOldBitmap;
 NewBitmap.LoadBitmap(IDB_ABOUT);
 BITMAP bmp;  NewBitmap.GetBitmap(&bmp);
 MemDC.CreateCompatibleDC(pDC);
 pOldBitmap = MemDC.SelectObject(&NewBitmap);

     
要解决这个问题可以用DirectX,这里不做介绍.我要讲的是用缓冲机制解决:
  
   1.同上面的2,3,4:
    
        CBitmap bmp;
        bmp.LoadBitmap(ID);
        CDC memDC;
        memDC.CreateCompatibleDC(pDC);
        memDC.SelectObject(&bmp);
      
    
2.创建一个与你的窗口一样大的(如果是全屏的那就是整个屏幕的大小)兼容DC(及用于缓
       冲的DC)和兼容位图,并将兼容位图选入兼容DC。    
         
     CBitmap BkMap;
     BkMap.CreateCompatibleBitmap(pDC,w,h);//w,h表示窗口的宽和高
     CDC BkDC;
     BkDC.CreateCompatibleDC(pDC);
     BkDC.SelectObject(&BkMap); 

 

 MemDC.SetMapMode(MM_ANISOTROPIC);
 MemDC.SetWindowExt(bmp.bmWidth, bmp.bmHeight);

    3.在缓冲DC上贴图
 
     BkDC.BitBlt(x,y,width,height,&memDC,0,0,SRCCOPY);

 

 MemDC.SetViewportExt(bmp.bmWidth, -bmp.bmHeight);
 MemDC.SetViewportOrg(bmp.bmWidth/2, bmp.bmHeight);
 pDC->BitBlt(-rect.Width()/2, -rect.Height()/2, rect.Width(),
rect.Height(), &MemDC, -bmp.bmWidth/2, -bmp.bmHeight/2, SRCCOPY);
 MemDC.SelectObject(pOldBitmap);

     如果有多张图片要同时贴在屏幕上,如有背景图,前景图,还可能有许
       多小图片,那也要把这些图全部贴在这个缓冲DC上。

2 .在视图类添加如下代码:

 

    4.把缓冲DC的图片贴到屏幕。
    
       pDC->BitBlt(0,0,w,h,&BkDC,0,0,SRCCOPY); 
    
  
  这就完成了缓冲,就是说贴每个图的过程全部都在缓冲DC上面完成,等所有的图
       都贴到了缓冲DC上后,就把缓冲DC上的图一次性的贴到屏幕上。    
   
 但是这样还会存在一个问题,假设一个运动的物体运动过一个轨迹的话,那么这
      
个轨迹上面都会有这个物体,因为物体经过后,原来地方的图片并没有被搽除。
  
  要解决这个问题也很简单,只要在每次往缓冲DC上面贴图的时候把缓冲DC”搽“
      
一下就可以了:怎么搽?往上面贴一张同样大小的白色图片不就把上面的内容搽?也可以用FillXXX函数进行填充。

[cpp] view
plaincopy

双缓冲机制
 CRect rect;
 GetClientRect(&rect);
 pDC->SetMapMode(MM_ANISOTROPIC);
 pDC->SetWindowExt(rect.Width(),rect.Height());
 pDC->SetViewportExt(rect.Width(),-rect.Height());
 pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);

  1. void CSetBkMapView::OnDraw(CDC* pDC)  
  2. {  
  3.     CSetBkMapDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     if (!pDoc)  
  6.         return;  
  7.     // TODO: 在此处为本机数据添加绘制代码  
  8. // 获取客户区大小  
  9.     CRect rcClient;  
  10.     GetClientRect(&rcClient);  
  11.     CBitmap bmp; // 定义一个位图变量  
  12.     CBitmap* oldBmp;  
  13.     CDC memDC;  
  14.     bmp.LoadBitmap(IDB_BITMAP1);  
  15.     // 获取位图信息  
  16.     BITMAP bm;  
  17.     bmp.GetBitmap( &bm );  
  18.     memDC.CreateCompatibleDC(pDC);  
  19.     oldBmp=memDC.SelectObject(&bmp); // 将位图资源选入内存DC  
  20.   // 在客户区绘制位图  
  21.     pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&memDC,0,0,SRCCOPY);  memDC.SelectObject(oldBmp);// 将旧位图选回设备环境  
  22.     bmp.DeleteObject(); // 删除位图资源  
  23.     memDC.DeleteDC(); // 删除内存DC  
  24. }  

 CDC memDC;//声明内存DC
 CBitmap NewBitmap,*pOldBitmap;
 memDC.CreateCompatibleDC(pDC);//创建一个与显示DC兼容的内存DC
 NewBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//创建兼容内存位图
 pOldBitmap=memDC.SelectObject(&NewBitmap);//将兼容位图选入内存DC
 memDC.FillSolidRect(rect, RGB(0, 0,
0));//按原来背景色填充客户区,否则是黑色

 

 rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
 memDC.SetMapMode(MM_ANISOTROPIC);//内存DC自定义坐标系
 memDC.SetWindowExt(rect.Width(),rect.Height());
 memDC.SetViewportExt(rect.Width(),-rect.Height());
 memDC.SetViewportOrg(rect.Width()/2,rect.Height()/2);

效果图如下:

 DrawObject(&memDC);
 pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,-rect.Width()/2,-rect.Height()/2,SRCCOPY);
//将内存DC中的位图拷贝到设备DC
 memDC.SelectObject(pOldBitmap);

    澳门新葡亰网址下载 1

两段代码都用到CreateCompatibleDC(),可是它们是有区别的,相关部分看下面

 

CBitmap::GetBitmap int GetBitmap( BITMAP* pBitMap );
返回值:成功非零,失败零
参数:pBitMap 指向BITMAP结构体的指针,必须是非空
说明:调用这个成员函数来检索一个CBitmap对象的信息。信息通过BITMAP结构体返回

CDC::CreateCompatibleDC  virtual BOOL CreateCompatibleDC( CDC* pDC );
返回值:成功非零,失败零
参数: pDC
一个指向设备上下文的指针。如果是空,函数创建一个与显示设备上下文相兼容的内存设备上下文
说明:
创建一个和pDC指向的设备上下文相兼容的内存设备上下文。一个内存设备上下文是一个代表一个显示面内存块。它可以用来在内存中准备图片,当要拷贝它们到实际的相兼容的设备的上面。
当一个内存设备上下文被创建,GDI自动选择一个1×1单色像素位图。GDI输出函数可以和内存设备上下文一起使用当且仅当一个位图创建并选择到该上下文。
这个函数只能用来为可以支持光栅操作
的设备创建兼容设备上下文。查看CDC:BitBlt成员函数有关在设备上下文间表的传输信息。决定一个设备上下文是否支持光栅操作,要看成员函数::GetDeviceCaps的RC_BITBLT光栅能力。

 

CBitmap::CreateCompatibleBitmap BOOL CreateCompatibleBitmap( CDC* pDC,
int nWidth, int nHeight );
返回值 成功非零,失败零
参数: pDC 指定设备上下文 nWidth 指定bitmap的像素宽 nHeight
指定bitmap的像素高
说明:
初始化一个与pDC指定的设备相兼容的位图。位图和指定的设备上下文有相同数量的颜色值或相同的格式(每个像素色彩位数相同)。它可以被任何内存设备(与pDC所指定的某个设备相兼容)选为当前位图。
如果pDC是内存设备上下文,位图返回该设备上下文中和当前所选位图具有相同的格式的bitmap。一个“内存设备上下文”是一块代表一个显示面的内存。它可以用来在内存中准备图片,在拷贝它们到实际的相兼容的设备的上面之前。
当一个内存设备上下文被创建了,GDI自动为它选择一个单色的备用bitmap。
由于一个颜色内存设备上下文可以选择彩色或单色位图,CreateCompatibleBitmap函数返回的位图格式并不总是相同的,然而,
一个与nonmemory设备上下文兼容的位图的格式总是在设备的格式中。
当你用CreateCompatibleBitmap函数完成CBitmap对象创建,首先将位图选出设备上下文,然后删除CBitmap对象。

CDC::CreateCompatibleDC和CBitmap::CreateCompatibleBitmap 区别
一个是设备上下文,一个是位图;这是最大的区别

CWnd::Invalidate void Invalidate( BOOL bErase = TRUE );
参数: bErase 指定更新区域内的背景是否被删除
说明:
Wnd的整个客户区无效。当WM_PAINT消息出现,客户区被标记为绘画。该地区可以通过ValidateRect和ValidateRgn成员函数在
WM_PAINT消息发生之前验证。
bErase参数指定当更新区域被处理时更新区域内的背景是否被删除。如果bErase是真的,BeginPaint成员函数被调用时背景要删除;如果bErase是假的,背景保持不变。如果bErase适用于任何更新区域的一部分,整个地区(不仅在给定的部分)的背景都要删除。
只要CWnd更新区域并不是空而且没有其他消息的应用程序队列在该窗口,Windows发送WM_PAINT消息。

 

双缓冲原理是先在内存设备上下文将图形绘制好,然后将它拷到显示设备上下文,它的代码部分要看仔细。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图