我住包子山

this->blog.MoveTo("blog.baozishan.in")

VC++编程内幕学习心得(2)--上

第六章 GDI,字体,位图

第五章的例子就有简单的CDC类型的应用

这次更加详细的总结了设备环境类型及其应用
常用类型CClientDCCWindowDC,算做显示设备
函数 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.cppblog.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.cppblog.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(+),如图

 clip_image001

获得一个DC的字体高度信息可以传TEXTMETRIC结构指针到DC函数GetTextMetrics,这时的TEXTMETRIC结构就有图上的这些信息了~~晚上忙了半天,就写了这么多..就到这里.

                               gohan made 11.26

posted on 2007-11-26 21:46 Gohan 阅读(2550) 评论(0)  编辑 收藏 引用 所属分类: MFC/SDK


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理