Visual C++提供的应用程序框架虽然可以自动生成多文档(MDI)的应用程序,但是程序的界面比较单调,如果能够在主框架中添加上彩色位图,一定能够大大改观程序的界面效果。目前也有些编程资料涉及到如何在MDI应用程序的主框架中添加彩色位图,但具体实践过程中都有一些小问题,为此,本实例介绍了一种比较简单可行的方法,可以在程序中圆满地实现这种功能,程序运行后的界面效果如图一所示:
一、实现方法
在多文档界面下,应用程序会自动生成一个新的子窗口,而一个实际的应用系统往往是由用户操作后再生成新的窗口。为了去掉开始的子窗口,方便在主框架中添加彩色位图,可在应用程序BOOL CImageprocess2App::InitInstance()函数里面
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; |
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);
添加代码: if(pMsg->hwnd==m_hWndMDIClient && pMsg->message==WM_PAINT)
PostMessage(WM_PAINT);
4、 用ClassWizard向主框架类添加消息响应函数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();
}
5、 添加代码,编译运行程序。