在VC++项目中为MDI主框架窗口添加位图(通过截获MDICLIENT的WM_PAINT消息)

在VC++项目中为MDI主框架窗口添加位图

2005-12-02 08:53 作者:刘涛 出处:天极开发 责任编辑:方舟
<script src="http://ucpn.yesky.com/js.ng/site=yesky&node_yesky=412&page=cont&area=y_inner_under_banner&format=banner&num=1"></script> <script src="http://ucpn.yesky.com/js.ng/site=yesky&node_yesky=412&page=cont&area=y_inner_under_banner&format=banner&num=2"></script>

 

<script src="http://ucpn.yesky.com/js.ng/site=yesky&node_yesky=412&page=cont&area=yesky_inner_pip&format=picinpic&num=1"></script>

  Visual C++提供的应用程序框架虽然可以自动生成多文档(MDI)的应用程序,但是程序的界面比较单调,如果能够在主框架中添加上彩色位图,一定能够大大改观程 序的界面效果。目前也有些编程资料涉及到如何在MDI应用程序的主框架中添加彩色位图,但具体实践过程中都有一些小问题,为此,本实例介绍了一种比较简单 可行的方法,可以在程序中圆满地实现这种功能,程序运行后的界面效果如图一所示:


图一、添加彩色位图后的程序界面


  一、实现方法

  在多文档界面下,应用程序会自动生成一个新的子窗口,而一个实际的应用系统往往是由用户操作后再生成新的窗口。为了去掉开始的子窗口,方便在主框架中添加彩色位图,可在应用程序文件分析命令行的语句

CcommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
cmdInfo.m_nShellCommand=CcommandLineInfo::FileNothing;


  这时候编译运行程序就会反响去掉子窗口只剩下主框架窗口了。因为在多文档界面中,系统生成两个菜单:一个是用户的菜单,另一个是系统主框架菜单。通常用户工作在用户菜单。为了保证菜单界面不变,可修改主框架菜单资源,使其与用户菜单保持一致。

   下面我们进入正题,如何在主框架中添加位图。首先要清楚对于一个MDI应用程序的主框架窗口来说,它包含一个特殊的子窗口,称为MDICLIENT窗 口,应用程序的主框架类中有一个成员变量m_hWndMDIClient 指的就是MDICLIENT窗口。MDICLIENT窗口负责管理主框架窗口的客户区。直接对MDI客户窗口编程有一定的难度,原因是 MDIFrameWnd的客户区完全被MDICLIENT窗口覆盖掉了。正因为上述原因,MDI主窗口类MDIFrameWnd的背景色和光标都不起作 用。同时,微软的MFC并不支持将MDICLIENT窗口作为子类,MDICLIENT窗口只能使用标准的背景色和光标,所以对MDI客户窗口编程不能象 对普通窗口那样简单地重载WM_PAINT的消息处理函数。

  如何解决上述问题呢?解决的方法是我们可以在主框架窗口中截获关于 MDICLIENT窗口的重画消息,然后加入自己设计的代码。例如重载PreTranslateMessage(MSG* pMsg)函数,截获MDI客户窗口WM_PAINT消息,在这个函数中向主框架窗口发送WM_PAINT消息,在该消息的处理函数中实现彩色位图的显 示。PreTranslateMessage()是消息在送给TranslateMessage()函数之前被调用的,绝大多数本窗口的消息都要通过这 里,比较常用,当你需要在MFC之前处理某些消息时,常常要在这里添加代码。

  需要读者注意的是,不仅要在WM_PAINT消息响应函 数中显示图像,还要在主框架类CMainFrame::OnCreate()函数中处理显示函数的代码,否则程序运行后仅显示灰色的背景,只有在窗口改变 大小,需要重画时才显示出彩色位图。为什么会这样呢?笔者分析可能是框架的后续处理将最初绘制的彩色位图覆盖掉了。

  显示位图的时候用 到了位图类CBitmap,CBitmap类封装了WINDOWS的图形设备接口(GDI)中的位图,并提供了很多操作位图的操作。我们还会用到它的一个 函数LoadImage(),这个函数可以读入icon、cursor或bitmap,如果函数调用成功则返回读入的对象的句柄。此函数的原型如下:

BOOL LoadBitmap( LPCTSTR lpszResourceName );
BOOL LoadBitmap( UINT nIDResource );


  通过上面函数的定义,我们应该有一个思路了,要想加载位图资源可以有两种方式,一种是将位图导入到我们的资源文件中,一种直接从文件加载它。例如加载位图资源的方法如下:

//从资源文件加载位图
CBitmap m_bitmap; //建立一个位图对象;
m_bitmap.DeleteObject();
//调用CGdiObject的DeleteObject函数将以前的BITMAP对象删除。
m_bitmap.LoadBitmap(nBitmapID);//载入指定ID的图象资源nBitmapID是资源的ID;


  位图对象建立了,下面要作的是显示它,这便会用到设备环境。显示位图的步骤如下所示(注意两个DC的定义):

  1. 建立一个设备DC1,用来显示位图,它与某个要显示图像的窗口相关联;

  2. 建立一个内存DC2,它要与设备DC1相兼容;

  3. 建立一个位图对象,并载入位图;

  4. 选择位图对象选择到内存DC2中,最后通过StretchBlt()函数将内存DC的位图显示到设备DC上;

StretchBlt()函数的原型和参数说明如下:
BOOL StretchBlt( HDC hdcDest, //目标设备句柄;
int nXOriginDest, //目标矩形左上角的X坐标;
int nYOriginDest, //目标矩形左上角的Y坐标;
int nWidthDest, //目标矩形的宽度;
int nHeightDest, //目标矩形的高度;
HDC hdcSrc, //源设备句柄;
int nXOriginSrc, //源矩形左上角的X坐标;
int nYOriginSrc, //源矩形左上角的Y坐标;
int nWidthSrc, //源矩形的宽度;
int nHeightSrc, //源矩形的高度;
DWORD dwRop //光栅运算操作;);


   StretchBlt()函数的头文件为"wingdi.h"。其中,它的dwRop参数有15种操作,最常用的就是拷贝运算SRCCOPY了。当源设 备和目标设备指定的矩形大小不相等时,函数会根据源矩形和目标矩形的大小比例对位图进行放大或缩小操作后,拷贝到目标设备中。这里再通俗的解释一下句柄, 句柄是系统用来识别不同资源的一个唯一的识别码,通过它系统便可以快速正确的找到所要的资源。可以理解为指向资源对象的特殊指针。  

  二、编程步骤

  1、 启动Visual C++6.0,生成一个多文档的应用程序,将程序命名为"ShowBmp";

  2、 向程序添加256色彩色位图资源,命名为IDB_BITMAP1;

  3、 用Class Wizard向程序的主框架类CMainFrame添加函数CMainFrame::PreTranslateMessage(MSG* pMsg);

  4、 用ClassWizard向主框架类添加函数CMainFrame::OnPaint();

  5、 添加代码,编译运行程序。

 

三、程序代码

/
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
  return -1;
 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
WS_VISIBLE | CBRS_TOP| CBRS_GRIPPER |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
 {
  TRACE0("Failed to create toolbar/n");
  return -1; // fail to create
 }
 if (!m_wndStatusBar.Create(this) ||!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
 {
  TRACE0("Failed to create status bar/n");
  return -1; // fail to create
 }
 // TODO: Delete these three lines if you don't want the toolbar to
 // be dockable
 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
 EnableDocking(CBRS_ALIGN_ANY);
 DockControlBar(&m_wndToolBar);
 CDC dc, memdc;
 dc.m_hDC=::GetDC(this->m_hWndMDIClient);
 CRect rect;
 CBitmap bitmap;
 BITMAP szbitmap;
 bitmap.LoadBitmap(IDB_BITMAP1);
 bitmap.GetObject(sizeof(BITMAP),&szbitmap);
 CSize size(szbitmap.bmWidth,szbitmap.bmHeight);
 memdc.CreateCompatibleDC(&dc);
 CBitmap *oldbitmap=memdc.SelectObject(&bitmap);
 GetClientRect(&rect);
 StretchBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),
 memdc.m_hDC,0,0,size.cx,size.cy,SRCCOPY);
 memdc.SelectObject(oldbitmap);
 memdc.DeleteDC();
 dc.DeleteDC();
 return 0;
}
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 if(pMsg->hwnd==m_hWndMDIClient && pMsg->message==WM_PAINT)
  PostMessage(WM_PAINT);
 return CMDIFrameWnd::PreTranslateMessage(pMsg);
}

void CMainFrame::OnPaint()
{
 CDC dc, memdc;
 dc.m_hDC=::GetDC(this->m_hWndMDIClient);
 CRect rect;
 CBitmap bitmap;
 BITMAP szbitmap;
 bitmap.LoadBitmap(IDB_BITMAP1);
 bitmap.GetObject(sizeof(BITMAP),&szbitmap);
 CSize size(szbitmap.bmWidth,szbitmap.bmHeight);
 memdc.CreateCompatibleDC(&dc);
 CBitmap *oldbitmap=memdc.SelectObject(&bitmap);
 GetClientRect(&rect);
 StretchBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),
 memdc.m_hDC,0,0,size.cx,size.cy,SRCCOPY);
 memdc.SelectObject(oldbitmap);
 memdc.DeleteDC();
 dc.DeleteDC();
 CMDIFrameWnd::OnPaint();
}


  四、小结

  本实例通过在MDI应用程序的主框架中显示彩色位图作为背景,讲述了图像资源显示的方法,读者朋友可以以此展开,将彩色位图显示到不同的控件上,如按钮、对话框等,同时灵活运用各种显示方式,取得一些意想不到的效果。

 

 

摘自:http://dev.yesky.com/292/2218792_1.shtml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值