显示所有种类bmp位图的程序DisplayBmp过程详解
1.新建一个基于多文档的项目DisplayBmp,CDisplayBmpView类的基类是CscrollView类。
2.将事先写好的DIBAPI.H和DIBAPI.CPP两个文件增加到项目中。这两个文件声明和定义了DIB处理函数。
3.String Table中的字符串资源IDR_DISPLATYPE修改为:(为了能打开.bmp格式的文件)
\nDib\nDib\nDib Files (*.bmp; *.dib)\n.bmp\nDisplayBmp.Document\nDisplayBmp Document
4.在DisplayBmpDoc.h文件中增加如下语句:(此类中增加成员变量表示DIB数据块内存句柄)
public:
HANDLE m_hDIB;
一定要在构造函数中对它初始化:m_hDIB=NULL;否则就让你死都不知道怎么死的
5.在DisplayBmpDoc.h中增加如下语句:
public:
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
virtual BOOL OnSaveDocument(LPCTSTR lpszPathName);
在DisplayBmpDoc.cpp中添加如下语句
#include "dibapi.h"
BOOL CDisplayBmpDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
m_hDIB = LoadDIB(lpszPathName);
if (m_hDIB == NULL)
{
// may not be DIB format
return FALSE;
}
SetPathName(lpszPathName);
SetModifiedFlag(FALSE); // start off with unmodified
return TRUE;
}
BOOL CDisplayBmpDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
return SaveDIB(m_hDIB, lpszPathName);
}
以上语句的作用是重载了成员函数OnOpenDocument和OnSaveDocument,分别调用了我们定义的LoadDIB和SaveDIB来读写DIB文件,所以还要包含头文件"dibapi.h"。
6.在DisplayBmpView.h中添加:
public:
CRect m_rcDIB;即为此类添加一个成员变量
将CDisplayBmpView类中的函数OnInitialUpdate()修改为:
void CDisplayBmpView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CDisplayBmpDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CSize sizeTotal;
if (pDoc->m_hDIB != NULL)
{
LPBITMAPINFOHEADER lpDIB = (LPBITMAPINFOHEADER)GlobalLock(pDoc->m_hDIB);
m_rcDIB.left = 0;
m_rcDIB.top = 0;
sizeTotal.cx = m_rcDIB.right = ((LPBITMAPINFOHEADER)lpDIB)->biWidth;
sizeTotal.cy = m_rcDIB.bottom = ((LPBITMAPINFOHEADER)lpDIB)->biHeight;
GlobalUnlock(pDoc->m_hDIB);
}
else
{
m_rcDIB.SetRectEmpty();
sizeTotal.cx = sizeTotal.cy = 100;
}
SetScrollSizes(MM_TEXT, sizeTotal);
}
装入DIB文件时,OnInitialUpdate函数会首先调用
7.DisplayBmpView.cpp文件中添加语句
#include "dibapi.h"
View类的OnDraw函数修改为:
void CDisplayBmpView::OnDraw(CDC* pDC)
{
CDisplayBmpDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (pDoc->m_hDIB == NULL)
return;
PaintDIB(pDC->GetSafeHdc(),
m_rcDIB,
pDoc->m_hDIB,
m_rcDIB,
NULL,
SRCCOPY);
}
8.MainFrm.h中定义:“#define WM_REALIZEPAL (WM_USER + 0x100)”。当系统调色板已被修改时,主框窗口将向视发送WM_REALIZEPAL消息。在CDisplayBmpView类
中增加响应该消息的函数OnRealizePal和相应的消息映射,代码如下
LRESULT CDisplayBmpView::OnRealizePal(WPARAM wParam, LPARAM lParam)
{
ASSERT(wParam != NULL);
CDisplayBmpDoc* pDoc = GetDocument();
if (pDoc->m_hDIB == NULL)
return 0L; // must be a new document
LPBYTE lpbi = (LPBYTE)GlobalLock(pDoc->m_hDIB);
CPalette* pPal = CPalette::FromHandle(CreateDIBPalette(lpbi));
GlobalUnlock(pDoc->m_hDIB);
if (pPal != NULL)
{
CWnd* pAppFrame = AfxGetApp()->m_pMainWnd;
CClientDC appDC(pAppFrame);
// All views but one should be a background palette.
// wParam contains a handle to the active view, so the SelectPalette
// bForceBackground flag is FALSE only if wParam == m_hWnd (this view)
CPalette* oldPalette = appDC.SelectPalette(pPal, ((HWND)wParam) != m_hWnd);
if (oldPalette != NULL)
{
UINT nColorsChanged = appDC.RealizePalette();
if (nColorsChanged > 0)
GetDocument()->UpdateAllViews(NULL);
appDC.SelectPalette(oldPalette, TRUE);
}
else
{
TRACE0("\tSelectPalette failed!\n");
}
}
return 0L;
}
在 DisplayBmpView.h添加如下代码
protected:
afx_msg LRESULT OnRealizePal(WPARAM wParam, LPARAM lParam);
当系统调色板被修改时,主框收到系统的WM_PALETECHANGED和WM_QUERYNEWPALETTE消息,主框窗口通过下面的函数将向视发送WM_REALIZEPAL消息,OnRealizePal函数响应WM_REALIZEPAL消息。
9.添加响应WM_PALETECHANGED和WM_QUERYNEWPALETTE消息的函数,当系统察觉调色板发生变化时,会向程序的主框窗口发送这两个消息,然后由主框窗口通知各视窗。
在MainFrm.cpp中添加如下代码:
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{
CMDIFrameWnd::OnPaletteChanged(pFocusWnd);
// always realize the palette for the active view
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
return; // no active MDI child frame
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);
// notify all child windows that the palette has changed
SendMessageToDescendants(WM_REALIZEPAL, (WPARAM)pView->m_hWnd);
}
BOOL CMainFrame::OnQueryNewPalette()
{
// always realize the palette for the active view
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
return FALSE; // no active MDI child frame (no new palette)
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);
// just notify the target view
pView->SendMessage(WM_REALIZEPAL, (WPARAM)pView->m_hWnd);
return TRUE;
}
在MainFrm.h中添加如下代码
protected:
afx_msg void OnPaletteChanged(CWnd* pFocusWnd);
afx_msg BOOL OnQueryNewPalette();