第六章 GDI,字體,位圖
第五章的例子就有簡單的CDC類型的應用
這次更加詳細的總結了設備環境類型及其應用
常用類型CClientDC和CWindowDC,算做顯示設備
函數 CDC::GetClipBox(LPRECT lpRect)能夠獲取當前操作dc可見的區域矩形吧,我大概這樣子理解.當然,映射模式不同的情況得到的值也不一樣,是邏輯坐標單位
只有改寫視圖類的OnPaint類時才會用CPaintDC
GDI對象有許多
· CBitmap A bitmap is an array of bits in which one or more bits correspond to each display pixel. You can use bitmaps to represent images or to create brushes.
· CBrush A brush defines a bitmapped pattern of pixels that is used to fill areas with color.
· CFont A font is a complete collection of characters of a particular typeface and a particular size. Fonts are generally stored on disk as resources, and some are device-specific.
· CPalette A palette is a color-mapping interface that allows an application to take full advantage of the color capability of an output device without interfering with other applications.
· CPen A pen is a tool for drawing lines and shape borders. You can specify a pen’s color and thickness and whether it draws solid, dotted, or dashed lines.
· CRgn A region is an area whose shape is a polygon, an ellipse, or a combination of polygons and ellipses. You can use regions for filling, clipping, and mouse hit-testing.
這些對象都是派生自CGdiObject類.這些對象構造方法有的直接定義就算構造成功,有的需要定義完之后進一步調用創建函數.
void CCDCcreateView::OnDraw(CDC* pDC)
{
pDC->TextOut(0,0,m_szStr);
CPen newPen(PS_ALTERNATE,1,RGB(0,255,0));
CPen* pOldPen = pDC->SelectObject(&newPen);
for(int i=0;i<=100;i+=10)
{
pDC->MoveTo(i,0);pDC->LineTo(i,100);
pDC->MoveTo(0,i);pDC->LineTo(100,i);
}//畫格子100*100,一個格子為9*9
CCDCcreateDoc* pDoc = GetDocument();
pDC->SelectObject(pOldPen);
ASSERT_VALID(pDoc);
if (!pDoc)
return;
}
出了自建GDI對象還有庫存GDI對象(StockObject)
使用CDC::SelectStockObject方法選取
比如: pDC->SelectStockObject(BLACK_PEN);
其他的庫存對象都可以去查MSDN
關于GDI對象有效期,書中提到打印機和內存緩沖區等設備環境,如果只是在類中用一個成員變量指針保存GDI對象指針是不穩妥的,如果需要讓一個GDI對象保持有效性,需要保存一個GetSafeHandle()返回的一個句柄..書中的例子:
void CCDCcreateView::SwitchToCourier(CDC* pDC)
{
m_pPrintFont->CreateFont(30,10,0,0,400,FALSE,FALSE,
0,ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,DEFAULT_PITCH | FF_MODERN,
TEXT("Courier New")); //TrueType
CFont* pOldFont = pDC->SelectObject(m_pPrintFont);
m_hOldFont = (HFONT) pOldFont->GetSafeHandle();
}
m_hOldFont保存了之前CDC對象選用的字體配置的句柄,恢復的代碼如下
void CCDCcreateView::SwitchToOldFont(CDC* pDC)
{
if(m_hOldFont)
{
pDC->SelectObject(CFont::FromHandle(m_hOldFont));
}//調用CFont類型的FromHandle靜態成員函數
}
大概你應該會跟我一樣對于CreateFont這樣非常多的參數感到不知所措,那么請繼續往下看,從頭開始講解字體對象
GDI對象中包括字體對象,字體對象跟其他GDI對象在行為上都一樣.
在windows中字體有兩種,一種是TrueType字體跟設備無關,另一種和設備相關.System字體還有什么LinePrinter字體啥的.如果要讓字體以磅這個單位顯示或者打印,需要使用MM_TWIPS映射模式,1磅 = 1/72 英寸 = 20個 MM_TWIPS邏輯單位(1/1440英寸)
書上說實現打印和顯示得到精確的匹配很不容易做到,只有MM_TEXT的映射下,顯示和打印才能夠得到精確匹配,具體我不了解,以后實踐再說,現在還用不到打印
關于顯示器邏輯英寸和物理英寸,CDC成員函數GetDeviceCaps可以得到這些顯示參數
參數:HORZSIZE 物理寬度(mm),VERTSIZE物理高度(mm),HORZERES像素寬度,VERTRES像素高度(光柵行數),LOGPIXELSX,LOGPIXELSY,每邏輯英寸水平/垂直像素數
書上介紹了邏輯twips設置,
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1440,1440);//個人認為這個比例可以任意,只是個比例,大小自己愛好吧
pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),-pDC->GetDeviceCaps(LOGPIXELSY));
這三句話就設置成了邏輯twips,這個用來穩定字體比例,邏輯英寸水平/垂直的像素數決定了顯示字體的大小,注意的是默認的system字體固定了尺寸,不能根據邏輯像素值來調整大小TrueType可以調整;
仔細體會一下兩種twips映射,確實有所不同,邏輯的twips隨分辨率增大高越變越小,而標準twips映射大小不變,無論分辨率咋變.
下面就是本章第一個例子
我稍做了點改動
void CfontView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1440,1440);
pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),-pDC->GetDeviceCaps(LOGPIXELSY));
//pDC->SetMapMode(MM_TWIPS);
CView::OnPrepareDC(pDC, pInfo);
}
void CfontView::ShowFont(CDC* pDC, int& nPos, int nPoints)
{
TEXTMETRIC tm;
CFont fontText;
CString strText;
CSize sizeText;
fontText.CreateFont(nPoints * 20, 0, 0, 0, 400,FALSE,FALSE,0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,DEFAULT_PITCH|FF_SWISS,TEXT("Arial"));
CFont *pOldFont = /*(CFont*)*/pDC->SelectObject(&fontText);
pDC->GetTextMetrics(&tm);
TRACE("nPoints = %d, tmHeight = %d, tmInternalLeading = %d,"
" tmExternalLeading = %d\n", nPoints, tm.tmHeight, tm.tmInternalLeading, tm.tmExternalLeading);
strText.Format(TEXT("http://www.shnenglu.com/ withs %d-point"),nPoints);
sizeText = pDC->GetTextExtent(strText);
TRACE("width = %d, string height = %d\n", sizeText.cx, sizeText.cy);
pDC->TextOut(0, nPos, strText);
nPos-=tm.tmHeight + tm.tmExternalLeading;
fontText.DeleteObject();
fontText.CreateFont(-nPoints * 20, 0, 0, 0, 400,FALSE,FALSE,0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_SWISS,TEXT("Arial"));
/* CFont *pOldFont = *//*(CFont*)*/pDC->SelectObject(&fontText);
pDC->GetTextMetrics(&tm);
TRACE("nPoints = %d, tmHeight = %d, tmInternalLeading = %d,"
" tmExternalLeading = -%d\n", nPoints, tm.tmHeight, tm.tmInternalLeading, tm.tmExternalLeading);
strText.Format(TEXT("http://www.shnenglu.com/ withs %d-point minus Points"),nPoints);
sizeText = pDC->GetTextExtent(strText);
TRACE("width = %d, string height = %d\n", sizeText.cx, sizeText.cy);
pDC->TextOut(0, nPos, strText);
pDC->SelectObject(pOldFont);
nPos-=tm.tmHeight + tm.tmExternalLeading;
}
void CfontView::OnDraw(CDC* pDC)
{
int nPos = 0;
for(int i=6; i<=24; i+=2)
{
ShowFont(pDC, nPos, i);
}
CfontDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此處為本機數據添加繪制代碼
}
執行結果有點奇怪,CreateFont的高度用負數比用正數大一些..
其實書上有寫,CreateFont的第一個參數
(tmHeight – tmInternalLeading)(-數) = tmHeight(+數),如圖

獲得一個DC的字體高度信息可以傳TEXTMETRIC結構指針到DC函數GetTextMetrics,這時的TEXTMETRIC結構就有圖上的這些信息了~~晚上忙了半天,就寫了這么多..就到這里.
gohan made 11.26