MFC积累---20111105(关于设置背景图片、背景颜色插入背景音乐)

[cpp]  view plain copy
  1. CPaintDC dc(this);   
  2. CRect rect;   
  3. GetClientRect(&rect);   
  4. CDC dcMem;   
  5. dcMem.CreateCompatibleDC(&dc);   
  6. CBitmap bmpBackground;   
  7. bmpBackground.LoadBitmap(IDB_BITMAP1);   
  8. //IDB_BITMAP是你自己的图对应的ID  
  9. BITMAP bitmap;   
  10. bmpBackground.GetBitmap(&bitmap);   
  11. CBitmap *pbmpOld=dcMem.SelectObject(&bmpBackground);   
  12. dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  

设置断点跟踪程序,发现问题语句出现在

[cpp]  view plain copy
  1. CBitmap *pbmpOld=dcMem.SelectObject(&bmpBackground);   

经过分析之后,载入的是位图文件,我用的是的png文件,所以会报错,这样的小错误,一定切记切记!!

MFC中设置窗体的背景色,图片,插入音乐 

一、设置背景颜色的三种方法:
1、我们知道程序在运行的时候会调用OnPain函数,那么我们可以在这里设置背景颜色。
[html]  view plain copy
  1. void CFlipCardsDlg::OnPaint()  
  2. {  
  3. if (IsIconic())  
  4.  {  
  5. //保持不变  
  6.  }  
  7.  else  
  8.  {     
  9.   CRect   rc;  
  10.   GetClientRect( &rc );// 获取客户区  
  11.   CPaintDC dc(this);  
  12.   dc.FillSolidRect(&rc, RGB(0,160,0));   // 填充客户区颜色  
  13.   CDialog::OnPaint();            
  14.  }  
  15. }  

2、第二种方法只要一条语句,但是这里要注意这里绘制的颜色是针对程序中所有的对话框(如果是单文档的话,好像不行)
SetDialogBkColor(RGB(0,0,255),RGB(255,0,0));
// 前一个RGB是背景色,后一RGB是文本颜色该函数放在工程的APP文件的初始化函数中。


3、第三种方法,利用ClassWizard重载OnCtlColor(),即WM_CTLCOLOR消息在要着色的对话框中申明一个变量,CBRUSH  m_hbrush;然后在项目的Dlg类初始化函数中给m_hbrush赋值。m_brush.CreateSolidBrush(RGB(0, 255, 0));然后在OnCtlColor(...)返回该画刷就可以了,如下。

[html]  view plain copy
  1. HBRUSH CFlipCardsDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  2. {  
  3.  HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);  
  4.    
  5.  // TODO: Change any attributes of the DC here  
  6.  switch (nCtlColor)  
  7.  {  
  8.  case CTLCOLOR_DLG:  
  9.   HBRUSH aBrush;  
  10.   aBrush = CreateSolidBrush(RGB(0, 150, 0));  
  11.   hbr = aBrush;  
  12.   break;  
  13.  }  
  14.  // TODO: Return a different brush if the default is not desired  
  15.  return hbr;  
  16. }  

这样为对话框着色就可以实现了。

二、给MFC添加背景图图片代码:
定位到   void CXXXDlg::OnPaint(),在if()...else()中的else()下添加如下代码:
[html]  view plain copy
  1. //CDialog::OnPaint();//要禁止这个调用    
  2. CPaintDC  dc(this);    
  3. CRect  rect;    
  4. GetClientRect(&rect);    
  5. CDC  dcMem;    
  6. dcMem.CreateCompatibleDC(&dc);    
  7. CBitmap  bmpBackground;    
  8. bmpBackground.LoadBitmap(IDB_BITMAP);   
  9. //IDB_BITMAP是你自己的图对应的ID  
  10. BITMAP  bitmap;    
  11. bmpBackground.GetBitmap(&bitmap);    
  12. CBitmap  *pbmpOld=dcMem.SelectObject(&bmpBackground);   
  13. dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);    


三、MFC 中设置背景音乐问题

#include <mmsystem.h>
#pragma comment( lib, "Winmm.lib" )

PlaySound函数的声明为:

BOOL PlaySound(LPCSTR pszSound, HMODULE hmod,DWORD fdwSound);


第一种方法是直接播出声音文件,相应的代码为:
PlaySound("c://win95//media//The Microsoft Sound.wav", NULL, SND_FILENAME | SND_ASYNC);注意参数中的路径使用两个连续的反斜杠转义代表一个反斜杠。
 
第二种方法是把声音文件加入到资源中,然后从资源中播放声音。Visual C++支持WAVE型资源,用户在资源视图中单击鼠标右键并选择Import命令,然后在文件选择对话框中选择The Microsoft Sound.wav文件,则该文件就会被加入到WAVE资源中。假定声音资源的ID为IDR_STARTWIN,则下面的调用同样会输出启动声音:PlaySound((LPCTSTR)IDR_STARTWIN, AfxGetInstanceHandle(), SND_RESOURCE | SND_ASYNC);


第三种方法是用PlaySound播放系统声音,Windows启动的声音是由SystemStart定义的系统声音,因此可以用下面的方法播放启动声音:

PlaySound("SystemStart",NULL,SND_ALIAS|SND_ASYNC);函数sndPlaySound的功能与PlaySound类似,但少了一个参数。函数的声明为:BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound);除了不能指定资源名字外,参数lpszSound与PlaySound的是一样的。参数fuSound是如何播放声音的标志,可以是SND_ASYNC、SND_LOOP、SND_MEMORY、SND_NODEFAULT、SND_NOSTOP和SND_SYNC的组合,这些标志的含义与PlaySound的一样。


第四种方法:
sndPlaySound不能直接播放声音资源。要用该函数播放WAVE文件,可按下面的方式调用:sndPlaySound(“MYSOUND.WAV”,SND_ASYNC);自己把资源添在Debug文件夹里。先载入一张图片,ID为IDB_BITMAP2

TestDlg.h中:

CBrush m_brBk;//在public中定义

TestDlg.cpp中:
在初始化函数OnInitDialog()中加入:
[html]  view plain copy
  1. BOOL CTestDlg::OnInitDialog()  
  2. {  
  3. CDialog::OnInitDialog();  
  4. CBitmap bmp;  
  5. bmp.LoadBitmap(IDB_BITMAP2);  
  6. m_brBk.CreatePatternBrush(&bmp);  
  7. bmp.DeleteObject();  
  8. return TRUE; // return TRUE unless you set the focus to a control  
  9. }  

再打开类向导,找到WM_CTLCOLOR消息,重载得对应函数OnCtlColor(),
添加如下:
[html]  view plain copy
  1. HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  2. {  
  3. HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);  
  4. if (pWnd == this)  
  5. {  
  6. return m_brBk;  
  7. }  
  8. return hbr;  
  9. }  


按照上面的方法一路COPY下来运行,OK!并且由于图片是做为背景显示的,所以再添的按钮都能很好的显示出来,非常方便。总结一下其中出现的变量和函数。

CBrush:类CBrush封装了Windows图形设备接口(GDI)中的画刷,画刷也就是采取什么方案填充图形的背景的工具。

OnInitDialog ( ):用于对对话框类的变量的初始化(注意:是在产生对话框之前就初始化),是WM_INITDIALOG消息产生的消息处理函数,覆盖该函数可改变对话框初始设置。

用法:virtual BOOL OnInitDialog();返回值指定对话框是否对它的一个控件设置输入焦点。如果OnInitDialog返回非零值,Windows 将输入焦点设在对话框的第一个控件上,只有在对话框明确将输入焦点设在某控件上,应用返回0。

CBitmap:类CBitmap封装了Windows图形设备接口(GDI)中的位图,并且提供操纵位图的成员函数。

LoadBitmap ( ):CBitmap类的一个成员函数,从应用的可执行文件中加载一个命名的位图资源来初始化位图对象。用法:BOOL LoadBitmap( LPCTSTR lpszRecourceName );BOOL LoadBitmap( UINT nIDResource );返回值调用成功时返回非零值,否则为0。参数lpszResourceName指向一个包含了位图资源名字的字符串(该字符串以null结尾)。NIDResource指定位图资源中资源的ID号。本函数从应用的可执行文件中加载由lpszResourceName指定名字或者由nIDResource指定的ID号标志的位图资源。加载的位图被附在Cbitmap对象上。如果由lpszResourceName指定名字的对象不存在,或者没有足够的内存加载位图,函数将返回0。可以调用函数CgdiObject::DeleteObject删除由LoadBitmap加载的位图,否则Cbitmap的析构函数将删除该位图对象。

CreatePatternBrush ( ):CBrush类的一个成员函数,用位图指定的模式初始化画刷。用法:BOOL CreatePatternBrush( CBitmap* pBitmap );返回值调用成功时返回非零值,否则为0。参数pBitmap指定一个位图。本函数用位图指定的模式初始化画刷。此画刷随后就可用于任何支持光栅操作的设备上下文。由bBitmap指定的位图一般用以下的函数初始化:CBitmap:: CreateBitmap、CBitmap::CreateBitmapIndirect、CBitmap::LoadBitmap或Cbitmap::CreateCompatibleBitmap。

DeleteObject ( ):CgdiObject类的一个成员函数,从内存中删除附加给CGdiObject的Windows GDI对象,释放与此对象相关的系统存储空间。GdiObject类为各种Windows图形设备接口(GDI)对象,如位图、区域、画刷、画笔、调色板、字体等提供了一些基本类。我们不会直接构造一个CGdiObject对象,而是使用某一个派生类如CPen或CBrush创建。用法:

BOOL DeleteObject( );如果GDI对象被成功删除,则返回非零值,否则为0。通过释放附加的GDI对象占有的系统存储来删除它们。与CGdiObject对象有关的存储不受此调用的影响。如果CGdiObject对象正被选入设备上下文中,则应用不可对此对象调用DeleteObject,。当一个模式画刷被删除时,与之相关联的位图不被删除。位图必须被独立删除。

HBRUSH:数据类型,用于定义画刷句柄。在Windows环境中,句柄是用来标识项目的,这些项目包括:module, task,instance, file ,block of memory, menu, control, font, resource, icon, cursor, string, GDI object等,包括bitmap, brush, metafile, palette, pen, region以及设备描述表device context。实际上,句柄是一个标识符,用来表示对象或者项目,是一个32位的正整数。应用程序几乎总是通过调用一个Windows函数来获得一个句柄,之后其他的Windows函数就可以使用这个句柄,以引用相应的对象。

WM_CTLCOLOR消息:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notification message)。利用向导映射该消息产生函数:HBRUSH

 CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);参数pDC是TestDlg的设备上下文,pWnd是TestDlg中发送该消息的control指针,nCtlColor是Control的类型编码。WM_CTLCOLOR是系统在绘制控件的时候自动发送的,如果需要自定义,就截取这个消息并重载它的响应函数,用classWizard添加WM_CTLCOLOR消息然后编辑其OnCtlColor函数。这样Windows向应用程序发送消息WM_CTLCOLOR,应用程序处理WM_CTLCOLOR消息并返回一个用来绘画窗体背景的刷子句柄

[html]  view plain copy
  1. ====================================  
  2. //放在OnPaint()里  
  3. {//设置背景图片  
  4. CRect    rect;     
  5. GetClientRect(&rect);     
  6. CDC    *pDC=GetDC();     
  7. CDC    memdc;     
  8. memdc.CreateCompatibleDC(pDC);     
  9. CBitmap    bitmap;     
  10. //从资源中载入位图     
  11. bitmap.LoadBitmap(IDB_BITMAP1);     
  12. memdc.SelectObject(bitmap);     
  13. pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memdc,0,0,SRCCOPY);  
  14. }  
  15. ==========================================  


对于VC++文档、视结构中的视图,从用户的角度来看,只是可以改变大小、位置的普通窗口,同其他基于Windows应用程序的窗口是一样的;从程序员的 角度来看,视图并不是普通的窗口,而是从MFC库中CView类派生的类对象。像任何VC++对象一样,视图对象的行为由类的成员函数(数据成员)决定, 包括派生类中应用程序定义的函数和从基类继承来的函数。 提出问题 视图的背景一般来说是白色的,在缺省情况下,它和系统定义的颜色COLOR_WINDOW是一致的。设计者一般会希望自己的 程序可以让用户轻松地改变窗口背景颜色,或是用漂亮的图片来充填背景。我们可以用Windows函数SetSysColors来重新指定 COLOR_WINDOW所对应的实际颜色,来达到改变视图背景颜色的目的。但这样会同时改变其他应用程序的视图窗口背景,使得整个Windows系统的 颜色设置产生混乱。另外,我们可能会用以下方法来设置视图的背景颜色,即在CView的OnDraw函数中添写如下一段程序代码: 
[html]  view plain copy
  1. void CTestView::OnDraw(CDC* pDC)   
  2. {   
  3. CTestDoc* pDoc = GetDocument();   
  4. ASSERT_VALID(pDoc);   
  5. CRect rectClient;   
  6. CBrush brushBkColor;   
  7. GetClientRect(rectClient);   
  8. brushBkColor.CreateSolidBrush(RGB(255,0,0));   
  9. pDC->DPtoLP(rectClient);   
  10. pDC->FillRect(rectClient,&brushBkColor);   
  11. …   
  12. }   


这样可以达到改变当前应用程序的视图背景的目的,但同时也产生了一些不良影响,使得程序运行效果不尽如人意。

分析问题 
我们知道,在VC++的文档、视结构中,CView的OnDraw函数用于实现绝大部分图形绘制的工作。如果用户改变窗口尺寸, 或者显示隐藏的区域,OnDraw函数都将被调用来重画窗口。并且,当程序文档中的数据发生改变时,一般必须通过调用视图的Invalidate(或 InvalidateRect)成员函数来通知Windows所发生的改变,对Invalidate的调用也会触发对OnDraw函数的调用。正因为 OnDraw函数被频繁调用,所以在其执行时,每次都刷新填充一次视图客户区域,便会使屏幕不稳定,产生闪烁现象。 
笔者通过对VC++应用程 序框架结构和Windows消息映射系统的仔细研究,找到另外一种改变视图背景的方法,其执行效果比上述两种方法都好。其实在程序调用OnDraw函数之 前,会触发一个Windows消息:WM_ERASEBKGND,以擦除视图刷新区域。在缺省情况下,Windows系统使用视图窗口注册时窗口类中的成 员hbrBackground所描述的画刷来擦除屏幕,这一般会将屏幕刷新成COLOR_WINDOW所对应的颜色。因此,在OnDraw函数中设置背景 颜色的执行过程是这样的:先将屏幕刷新成COLOR_WINDOW所对应的颜色,接着又在OnDraw函数中填充其他颜色,这正是产生屏幕闪烁的根本原 因。


解决问题 
通过上述分析,我们应将视图背景颜色填充移到Windows消息:WM_ERASEBKGND所对应的消息映射函数中,而不是在 OnDraw函数中。我们可以通过下列步骤实现这一过程:在文档类中增加一成员变量m_viewBkColor保存当前背景颜色,同时增加两个成员函数 GetViewBkColor和SetViewBkColor对其进行读写操作。这样做的好处是可以对m_viewBkColor成员进行序列化,将其和 文档联系在一起,打开某一文档时,其背景将和上一次程序操作该文档时的背景保持一致。在视图类中为视图的Windows消息WM_ERASEBKGND增 加消息映射函数OnEraseBkgnd,代码如下: 
[html]  view plain copy
  1. BOOL CTestView::OnEraseBkgnd(CDC* pDC)    
  2. {   
  3. CRect rect;   
  4. CBrush brush;   
  5. brush.CreateSolidBrush(GetDocument()->GetViewBkColor());   
  6. pDC->GetClipBox(rect);   
  7. pDC->FillRect(rect,&brush);   
  8. return true;   
  9. }   


在该函数中不需要对客户区域矩形进行设备坐标到逻辑坐标的转换,并且Windows在调用该函数时会自动进行裁
剪区域的计算,使得需要刷新的屏幕面积达到最小。这样我们可以在程序中通过设计下列菜单函数轻松地改变视图背景的颜色,而且运行效果相当令人满意。 

[html]  view plain copy
  1. void CTestView::OnChangeViewBkcolor()    
  2. {   
  3. CColorDialog cdlg;   
  4. if(cdlg.DoModal()==IDOK)   
  5. {   
  6. GetDocument()->SetViewBkColor   
  7. (cdlg.GetColor());   
  8. InvalidateRect(NULL);   
  9. }   
  10. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值