接著上回開始
書上的第二個(gè)例子
直接貼我略加修改的代碼,后面附有注釋:
void Cfont2View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{//想說的是OnPrepareDC在每次調(diào)用OnDraw之前調(diào)用,可在里面進(jìn)行初始化的一些操作
CRect clientRect;
GetClientRect(clientRect);
pDC->SetMapMode(MM_ANISOTROPIC);//橫豎比恒定的可變比例映射
pDC->SetWindowExt(400,450);//窗口范圍固定,視口范圍如下,因此圖像(文字)會(huì)根據(jù)視口范圍改變比例
pDC->SetViewportExt(clientRect.right, -clientRect.bottom);//原書第二參數(shù)為正,我這里用負(fù)數(shù),為了和標(biāo)準(zhǔn)MM_TWIPS的x,y方向?qū)ι?/span>,x+,y-;
CPoint pt = pDC->GetViewportOrg();
ASSERT(pt.x==0&&pt.y==0);//pDC->SetViewportOrg(0,0);//原書上這樣寫,應(yīng)該有點(diǎn)多余,因?yàn)槌跏荚c(diǎn)就是0,0;
CView::OnPrepareDC(pDC, pInfo);
}
void Cfont2View::OnDraw(CDC* pDC)
{//OnDraw函數(shù)基本沒有變,只是用了一個(gè)nPos來一直計(jì)算新的字串位置
CFont fontT1,fontT2,fontT3,fontT4;
CFont * pOldFont = NULL;
TEXTMETRIC tm;
int nPos = 0;
fontT1.CreateFont(50,0,0,0,400,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH|FF_SWISS, TEXT("Arail"));
pOldFont = pDC->SelectObject(&fontT1);
pDC->TextOut(0,nPos,TEXT("This is Arial, default width"));
pDC->GetTextMetrics(&tm);
nPos-=tm.tmHeight+tm.tmExternalLeading;//找到下一個(gè)串的y坐標(biāo)
fontT2.CreateFont(50,0,0,0,400,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH|FF_MODERN, TEXT("Courier"));
pDC->SelectObject(&fontT2);
pDC->TextOut(0,nPos,TEXT("This is Courier, default width"));
pDC->GetTextMetrics(&tm);
nPos-=tm.tmHeight+tm.tmExternalLeading;
fontT3.CreateFont(50,10,0,0,400,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH|FF_ROMAN, TEXT("Courier"));
pDC->SelectObject(&fontT3);
pDC->TextOut(0,nPos,TEXT("This is generic Roman, variable width"));
pDC->GetTextMetrics(&tm);
nPos-=tm.tmHeight+tm.tmExternalLeading;
fontT4.CreateFont(50,0,0,0,400,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH|FF_MODERN, TEXT("LinePrinter"));
pDC->SelectObject(&fontT4);
pDC->TextOut(0,nPos,TEXT("This is LinePrinter, default width"));
pDC->GetTextMetrics(&tm);
nPos-=tm.tmHeight+tm.tmExternalLeading;
fontT5.CreateFont(50,0,0,0,400,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH|FF_MODERN, TEXT("Consolas"));
pDC->SelectObject(&fontT5);
pDC->TextOut(0,nPos,TEXT("Consolas Fonts, recommand by VS2005 official"));
pDC->SelectObject((CFont*)pOldFont);
Cfont2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此處為本機(jī)數(shù)據(jù)添加繪制代碼
}
這個(gè)例子大概就是這樣,截圖放出:

看著這個(gè)例子覺得字很丑,于是稍微改了一下背景色跟字體,一下就好看多了,呵呵,代碼很簡(jiǎn)單.需要在OnDraw或者OnPrepareDC中畫黑色背景,畫字體用CDC::SetBkMode設(shè)置透明背景,然后CDC::SetTextColor設(shè)置字體顏色為00FF00就可以了,呵呵

接下來就是一個(gè)關(guān)于深入了解ScrollView的一個(gè)例子(第三個(gè)例子)
這個(gè)例子建立時(shí)記得讓View從CScrollView中繼承
修改OnInitialUpdate()函數(shù)
void CgdiView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal(800,1050);
CSize sizePage(sizeTotal.cx/2,sizeTotal.cy/2);
CSize sizeLine(sizeTotal.cx/50,sizeTotal.cy/50);
SetScrollSizes(MM_LOENGLISH, sizeTotal,sizePage,sizeLine);
}
對(duì)于CScrollView類我仍然有一些疑惑,自己未能解決.在設(shè)置了ScrollSize以后,仍然可以將view拉長(zhǎng)導(dǎo)致超出ScrollSize,這樣不會(huì)顯示滾動(dòng)條,我試了半天也沒有解決問題,真的不知道該怎么辦..問題還是留在這里
其他實(shí)現(xiàn)如下:
View頭文件添加:
private:
const CSize m_sizeEllipse;
CPoint m_pointTopLeft;//橢圓外切矩形左上角坐標(biāo)
CSize m_sizeOffset;//鼠標(biāo)初始點(diǎn)中橢圓時(shí)與橢圓外切矩形左上角的偏移
BOOL m_bCaptured;//鼠標(biāo)按下的標(biāo)志
Cpp文件實(shí)現(xiàn):
void CgdiView::OnDraw(CDC* pDC)
{
CBrush brushHatch(HS_DIAGCROSS,RGB(255,0,0));//0xFF0000
CPoint point(0,0);
pDC->LPtoDP(&point);
pDC->SetBrushOrg(point);//繪制畫刷的原點(diǎn),如果不這樣寫,當(dāng)滾動(dòng)條滾動(dòng)時(shí),默認(rèn)繪制原點(diǎn)會(huì)變?yōu)楫?dāng)前區(qū)域的坐上點(diǎn)坐標(biāo)
pDC->SelectObject(&brushHatch);
pDC->Ellipse(CRect(m_pointTopLeft,m_sizeEllipse));
TRACE(TEXT("%d %d\n"),m_pointTopLeft.x,m_pointTopLeft.y);
pDC->SelectStockObject(BLACK_BRUSH);
pDC->Rectangle(100,-100,200,-200);//這個(gè)矩形為了方便查看重繪矩形,當(dāng)重繪時(shí)候矩黑色矩形部分會(huì)出現(xiàn)閃爍
CgdiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
}
void CgdiView::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
CRgn circle;
CClientDC dc(this);
OnPrepareDC(&dc);
dc.LPtoDP(rectEllipse);
circle.CreateEllipticRgnIndirect(rectEllipse);
if(circle.PtInRegion(point))
{
SetCapture();
m_bCaptured = TRUE;
CPoint pointTopLeft(m_pointTopLeft);
dc.LPtoDP(&pointTopLeft);
m_sizeOffset = point - pointTopLeft;
SetCursor(LoadCursor(NULL,IDC_CROSS));
}
CScrollView::OnLButtonDown(nFlags, point);
}
void CgdiView::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bCaptured)
{
ReleaseCapture();
m_bCaptured = FALSE;
}
CScrollView::OnLButtonUp(nFlags, point);
}
void CgdiView::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bCaptured)
{
CClientDC dc(this);
OnPrepareDC(&dc);
CRect rectOld(m_pointTopLeft, m_sizeEllipse+CSize(1,-1));
dc.LPtoDP(rectOld);
InvalidateRect(rectOld, TRUE);
m_pointTopLeft = point - m_sizeOffset;
dc.DPtoLP(&m_pointTopLeft);//注意這里有取地址而CRect沒有,是因?yàn)?/span>CRect類定義了一個(gè)隱式轉(zhuǎn)換,轉(zhuǎn)換成LPRECT,而CPoint沒定義
CRect rectNew(m_pointTopLeft, m_sizeEllipse);
dc.LPtoDP(rectNew);
InvalidateRect(rectNew,TRUE);
}
CScrollView::OnMouseMove(nFlags, point);
}
以下則是位圖的基本學(xué)習(xí)
這一節(jié)講位圖
關(guān)于創(chuàng)建設(shè)備無(wú)關(guān)位圖DIB.
關(guān)于DIB最好的資料是MSDN的幫助.
Windows 的兩種位圖:GDI位圖,DIB.
GDI位圖由MFC庫(kù)中的CBitmap類表示.在GDI位圖對(duì)象中有一個(gè)相關(guān)聯(lián)的windows數(shù)據(jù)結(jié)構(gòu),該數(shù)據(jù)結(jié)構(gòu)由windows的GDI模塊來維護(hù),它是設(shè)備相關(guān)的.應(yīng)用程序可以得到GDI位圖數(shù)據(jù)的一份拷貝,但其中每一位的安排完全依賴顯示設(shè)備.設(shè)備依賴的限制就是無(wú)法通過調(diào)制解調(diào)器,磁盤傳遞這樣的位圖..
操縱CBitmap跟其他GDI對(duì)象是一樣的簡(jiǎn)單..
但是MFC并沒有封裝DIB,所以需要用SDK的東西來使用DIB.原始使用DIB我覺得是一件很麻煩的事情,你需要了解一些系統(tǒng)調(diào)色板之類的知識(shí),有些Directx的書上ms有寫.讀取一個(gè)位圖文件需要先知道他的各種信息,之后根據(jù)信息為它建立大小合適的結(jié)構(gòu)存放他的位圖信息,根據(jù)這些為位圖設(shè)定位圖的調(diào)色版,在繪制位圖時(shí)有可能需要把位圖調(diào)色板讓系統(tǒng)使用,之后再恢復(fù)成原始的調(diào)色板,很多很復(fù)雜的操作..但是,這本書的作者提供給我們了一個(gè)他寫的CDib類,降低了開發(fā)的難度,節(jié)省了時(shí)間,網(wǎng)上ms有很多CDib的類:
我將附上去它的整個(gè)代碼部分,如果能研究好了這部分內(nèi)容應(yīng)該會(huì)有很大提高,目前我還沒研究太好..只是大概有那么點(diǎn)概念
頭文件直接貼在這兒
// cdib.h declaration for Inside Visual C++ CDib class
#ifndef _INSIDE_VISUAL_CPP_CDIB
#define _INSIDE_VISUAL_CPP_CDIB
class CDib : public CObject
{
enum Alloc {noAlloc, crtAlloc, heapAlloc};
DECLARE_SERIAL(CDib)
public:
LPVOID m_lpvColorTable;
HBITMAP m_hBitmap;
LPBYTE m_lpImage; // starting address of DIB bits
LPBITMAPINFOHEADER m_lpBMIH; // buffer containing the BITMAPINFOHEADER
private:
HGLOBAL m_hGlobal; // For external windows we need to free;
// could be allocated by this class or allocated externally
Alloc m_nBmihAlloc;
Alloc m_nImageAlloc;
DWORD m_dwSizeImage; // of bits -- not BITMAPINFOHEADER or BITMAPFILEHEADER
int m_nColorTableEntries;
HANDLE m_hFile;
HANDLE m_hMap;
LPVOID m_lpvFile;
HPALETTE m_hPalette;
public:
CDib();
CDib(CSize size, int nBitCount); // builds BITMAPINFOHEADER
~CDib();
int GetSizeImage() {return m_dwSizeImage;}
int GetSizeHeader()
{return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;}
CSize GetDimensions();
BOOL AttachMapFile(const char* strPathname, BOOL bShare = FALSE);
BOOL CopyToMapFile(const char* strPathname);
BOOL AttachMemory(LPVOID lpvMem, BOOL bMustDelete = FALSE, HGLOBAL hGlobal = NULL);
BOOL Draw(CDC* pDC, CPoint origin, CSize size); // until we implemnt CreateDibSection
HBITMAP CreateSection(CDC* pDC = NULL);
UINT UsePalette(CDC* pDC, BOOL bBackground = FALSE);
BOOL MakePalette();
BOOL SetSystemPalette(CDC* pDC);
BOOL Compress(CDC* pDC, BOOL bCompress = TRUE); // FALSE means decompress
HBITMAP CreateBitmap(CDC* pDC);
BOOL Read(CFile* pFile);
BOOL ReadSection(CFile* pFile, CDC* pDC = NULL);
BOOL Write(CFile* pFile);
void Serialize(CArchive& ar);
void Empty();
BOOL CDib::DrawDib(CDC* pDC, CPoint origin, CSize size);
private:
void DetachMapFile();
void ComputePaletteSize(int nBitCount);
void ComputeMetrics();
};
#endif // _INSIDE_VISUAL_CPP_CDIB
兩個(gè)構(gòu)造函數(shù):
CDib();
CDib(CSize size, int nBitCount); // builds BITMAPINFOHEADER
第一個(gè)沒有參數(shù)的構(gòu)造函數(shù)建立一個(gè)空的DIB對(duì)象,用來從文件或內(nèi)存載入DIB.
第二個(gè)帶有高寬,顏色位數(shù)的構(gòu)造函數(shù),可以用它的CreateSection,得到DIBSection.
其他Public的成員函數(shù):
BOOL AttachMapFile(const char* strPathname, BOOL bShare = FALSE);
BOOL AttachMemory(LPVOID lpvMem, BOOL bMustDelete = FALSE, HGLOBAL hGlobal = NULL);
從內(nèi)存映射文件讀出位圖/從內(nèi)存地址,有可能需要用全局句柄(HGLOBAL)讀出位圖
BOOL Compress(CDC* pDC, BOOL bCompress = TRUE); // FALSE means decompress
壓縮,解壓縮位圖
BOOL CopyToMapFile(const char* strPathname);
建立一個(gè)映射文件把當(dāng)前DIB內(nèi)容復(fù)制過去,當(dāng)文件對(duì)象關(guān)閉時(shí)(或CDib對(duì)象析構(gòu))真正寫入文件..
...省略很多函數(shù)說明,有問題可以查書,呵呵,下面介紹應(yīng)用CDib的方法
注意要鏈接"VFW32.lib,因?yàn)樵?/span>CDib中有(#include <vfw.h>)
使用CDib的方法:
調(diào)用Draw之前需要做的
m_pDib->UsePalette(pDC); // could be in palette msg handler
CSize sizeDib = m_pDib->GetDimensions();
pDC->StretchBlt(0, 0, sizeDib.cx, sizeDib.cy, &m_dcMem,
0, 0, sizeToDraw.cx, sizeToDraw.cy, SRCCOPY);
DIB的例子在下面:
建立工程使用的是CScrollView視圖,
CDib m_dibFile;
CDib m_dibResource;
兩個(gè)成員函數(shù),分別從資源文件載入位圖和從(映射)文件載入位圖
void CEx06dView::OnInitialUpdate()//初始化滾動(dòng)條跟映射模式,載入資源視圖
{
CScrollView::OnInitialUpdate();
CSize sizeTotal(30000, 40000); // 30-by-40 cm
CSize sizeLine = CSize(sizeTotal.cx / 100, sizeTotal.cy / 100);
SetScrollSizes(MM_HIMETRIC, sizeTotal, sizeTotal, sizeLine);
LPVOID lpvResource = (LPVOID) ::LoadResource(NULL,
::FindResource(NULL, MAKEINTRESOURCE(IDB_GOHAN),
RT_BITMAP));
m_dibResource.AttachMemory(lpvResource); // no need for
// ::LockResource
CClientDC dc(this);
TRACE("bits per pixel = %d\n", dc.GetDeviceCaps(BITSPIXEL));
}
OnDraw函數(shù),使用了兩個(gè)dib類型,第一個(gè)用SDK,StretchDIBits繪制圖像,第二個(gè)用CDib類型繪制圖像
void CEx06dView::OnDraw(CDC* pDC)
{
CEx06dDoc* pDoc = GetDocument();
BeginWaitCursor();
m_dibResource.UsePalette(pDC); // should be in palette
m_dibFile.UsePalette(pDC); // message handlers, not here
pDC->TextOut(0, 0,
"Press the left mouse button here to load a file.");
CSize sizeResourceDib = m_dibResource.GetDimensions();
sizeResourceDib.cx *= 30;
sizeResourceDib.cy *= -30;
//m_dibResource.Draw(pDC, CPoint(0, -800), sizeResourceDib);
pDC->SetStretchBltMode(COLORONCOLOR);
StretchDIBits(pDC->GetSafeHdc(),0,-800,sizeResourceDib.cx,sizeResourceDib.cy,0,0,sizeResourceDib.cx/30,sizeResourceDib.cy/-30,
m_dibResource.m_lpImage,(LPBITMAPINFO)m_dibResource.m_lpBMIH, DIB_RGB_COLORS, SRCCOPY);
CSize sizeFileDib = m_dibFile.GetDimensions();
sizeFileDib.cx *= 30;
sizeFileDib.cy *= -30;
m_dibFile.Draw(pDC, CPoint(1800, -800), sizeFileDib);
EndWaitCursor();
}
鼠標(biāo)左鍵點(diǎn)擊事件,你可以使用MEMORY_MAPPED_FILES宏定義,這時(shí)候用的是內(nèi)存映射文件,否則使用的就是文件,對(duì)應(yīng)的CDib方法分別為AttachMapFile, Read..
//#define MEMORY_MAPPED_FILES
void CEx06dView::OnLButtonDown(UINT nFlags, CPoint point)
{
CFileDialog dlg(TRUE, "bmp", "*.bmp");
if (dlg.DoModal() != IDOK) {
return;
}
#ifdef MEMORY_MAPPED_FILES
if (m_dibFile.AttachMapFile(dlg.GetPathName(),
TRUE) == TRUE) { // share
Invalidate();
}
#else
CFile file;
file.Open(dlg.GetPathName(), CFile::modeRead);
if (m_dibFile.Read(&file) == TRUE) {
Invalidate();
}
#endif // MEMORY_MAPPED_FILES
CClientDC dc(this);
m_dibFile.SetSystemPalette(&dc);
}

對(duì)于調(diào)色板的使用我并沒有很好的掌握,之后還會(huì)看看,如果想差不多會(huì)再補(bǔ)上,明天加上最后一小節(jié).