§3 Windows 图形设备接口及绘图
1. 响应 WM_PAINT 消息2. 图形设备接口 (GDI)
3. 使用设备描述表3. 获取设备描述表句柄5. CDC 及其派生类6. 使用 CDC 成员函数绘制文本7. 使用 CDC 成员函数绘制图形8. 正确使用 GDI 对象9. 设备坐标与逻辑坐标10. OpenGL 绘图
实验作业
1.习题 2,3,4
1. WM_PAINT 消息的产生 无效矩形
打开一个窗口 改变窗口大小 移动窗口 切换窗口 最小化、最大化窗口 调用 InvalidateRect 函数 调用 UpdateWindow 函数
2. 响应 WM_PAINT 消息 OnPaint
§3.1 响应 WM_PAINT 消息
§3.2 图形设备接口 (GDI)
1 . 图形设备接口—提供专门的数据结构即设备描述表( DC )和对 DC操作的绘图函数。
2 . 设备描述表( DC )—用于代表图形输出设备如显示屏、打印机;
3 . 设备无关性—利用 GDI ,所有的绘图操作都对设备描述表而不是具体的物理设备。
设备描述表• 一种专门用于代表图形输出设备 ( 如屏幕、打
印机和绘图仪等 ) 的数据结构– 画布– 绘图工具 ( 设备描述表属性 )
• 使用句柄 (HDC) 访问设备描述表 – 设置设备描述表属性– 绘制图形和文本
设备描述表属性 缺省值 设置属性值函数 获取属性值函数映射方式 MM_TEXT SetMapMode GetMapMode
窗口原点 (0,0) SetWindowOrg GetWindowOrgOffsetWindowOrg
视口原点 (0,0) SetViewportOrg GetViewportOrgOffsetViewportOrg
窗口限度 (1,1) SetWindowExt GetWindowExtSetMapMode
视口限度 (1,1) SetViewportExt GetViewportExtSetMapMode
画笔 BLACK_PE SelectObject SelectObject
画刷 WHITE_BRUSH SelectObject SelectObject
字模 SISTEM_FONT SelectObject SelectObject
位图 NONE SelectObject SelectObject
当前画笔位置 (0,0) MoveToLineTo
GetCurrentPosition
背景方式 OPAQUE SetBkMode GetBkMode
背景色彩 White SetBkColor GetBkColor
文本色彩 Black SetTextColor GetTextColor
作图方式 R2_COPYPEN SetROP2 GetROP2
伸展方式 BLACK_ONWHIE SetPollyFillMode GetPollyFillMode
多边形填充方式 ALTERNATE SetPollyFillMode GetPollyFillMode
字符间距 0 SetTextCharacterExtra GetTextCharacterExtra
画刷原点 (0,0)屏幕坐标 SetBrushOrg GetBrushOrg
裁剪区 NONE SelectObjectSelectClipRgnIntersectClipRectOffsetClipRgnExcludeClipRect
SelectObjectGetClipBox
设备描述表属性
GDI 对象• 画笔• 画刷• 字体• 位图• 裁剪区
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);
SetTextColor(hdc,RGB(255,0,0));
SetBkColor(hdc,RGB(0,0,255));
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
(1) 获取设备描述表句柄(2) 设置设备描述表属性(3) 调用绘图函数绘图(4) 释放设备描述表
3.3 使用设备描述表绘图
1. BeginPaint 和 EndPaint 函数 (1) BeginPaint function• 准备在窗口绘图• 获得代表窗口的设备描述表句柄• 把有关绘图的信息放到 PAINTSTRUCT 结构
变量中。• 响应 WM_PAINT 消息绘图,必须调用该函数
获取设备描述表句柄。
3.4 获取窗口设备描述表句柄
HDC BeginPaint( HWND hwnd, // handle to window
LPPAINTSTRUCT lpPaint // pointer to structure for paint information);
•函数原型:
PAINTSTRUCT • typedef struct tagPAINTSTRUCT {
HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32];
} PAINTSTRUCT
• 标志对指定窗口的绘图结束•释放设备描述表句柄•必须与 BeginPaint 函数成对调用•函数原型
BOOL EndPaint( HWND hWnd,
CONST PAINTSTRUCT *lpPaint
);
(2) EndPaint function
2.GetDC 和 RealeaseDC 函数( 1 ) GetDC function获取窗口设备描述表句柄用于响应非 WM_PAINT 消息绘图。函数原型:HDC GetDC( HWND hWnd );
( 2 ) ReleaseDC function
释放设备描述表句柄必须与 GetDC 函数成对调用函数原型:int ReleaseDC(HWND hWnd, // handle to window
HDC hDC // handle to device context);
3.5 CDC 及其派生类CDC: 封装了所有与设备描述表有关的
数据和操作。 绘图函数: Ellipse()… 文本输出: TextOut()… 设置设备描述表属性: SelectObject(),
SetTextColor()…
数据成员 m_hdc :设备描述表句柄。
CPaintDC: construction CWnd::BeginPaint destruction CWnd::EndPaint
CClientDC : construction CWnd::GetDC destruction CWnd::ReleaseDC
CWindowDC GetWindowDC ReleaseDC
3.6 GDI 对象与 CGDIObject类
• GDI 对象与句柄• 使用 GDI 对象• 使用 CGDIObject 类
句柄 对象HGDI OBJ 所有 GDI 对象HBRUSH 画刷HPEN 画笔HBI TMAP 位图HRGN 区域HPALETTE 调色板
GDI 对象与句柄
使用 GDI 对象基本规则 (1) 创建对象
(2) 用 SelectObject 函数把新创建的对象选入设备描述表,并保留原对象(3) 完成绘图函数的调用后,把旧对象选入设备描述表,置换出创建的对象(4) 删除创建的对象 , 由 DeleteObject 函数完成
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
HPEN hNewPen,hOldPen;
hNewPen=CreatePen(PS_DASH,1,RGB(255,0,0));
hOldPen=(HPEN)SelectObject(hdc,hNewPen);
MoveToEx(hdc,0,0,NULL);
LineTo(hdc,100,100);
hNewPen=(HPEN)SelectObject(hdc,hOldPen);
DeleteObject(hNewPen);
EndPaint(hWnd, &ps);
break;
使用 CGDIObject 类
• 数据成员 m_hObject• Attach 函数 Detach 函数• 派生类 : CPen 、 CBrush 、 CFont 、 C
Bitmap 、 CPallete 和 CRgn 类
逻辑坐标系TextOut(hdc, x,y,szBuffer,nLength) 设备坐标系 屏幕坐标系 窗口坐标系 窗口工作区坐标系 视口(设备坐标)与窗口(逻辑坐标)
§3.7 设备坐标与逻辑坐标
映像模式 定义了逻辑坐标与设备坐标的转换 CDC:: SetMapMode();
映射模式 逻辑单元 坐标轴方向MM_TEXT 象素 X:向右 Y:向下MM_I SOTROPI C 任意(X=Y) X:向右 Y:向上MM_ANI SOTROPI C 任意(X!=Y) X:向右 Y:向上MM_HI ENGLI SH 0. 001英寸 X:向右 Y:向上MM_HI METRI C 0. 01MM X:向右 Y:向上MM_LOENGLI SH 0. 01英寸 X:向右 Y:向上MM_LOMETRI C 0. 1MM X:可选 Y:可选MM_TWI PS 1/1440英寸 X:可选 Y:可选
• 窗口原点和视口原点– 调整逻辑坐标的原点
• 窗口限度和视口限度– 调整逻辑坐标轴的方向和单位
• 逻辑坐标与设备坐标的转换公式– xViewport=(xWindow-xWinOrg)*(xViewExt/xW
inExt)+xViewOrg;– yViewport=(yWindow-yWinOrg)*(yViewExt/y
WinExt)+xViewOrg;
• 设置逻辑坐标系的原点– SetViewportOrgEx 函数
BOOL SetViewportOrgEx(
HDC hdc, // 设备描述表句柄 int X, // 使用设备单位,视口原点的 X 坐标值 int Y, // 使用设备单位,视口原点的 Y 坐标值 LPPOINT lpPoint // 指向 POINT 结构变量,存放
原始的视口原点坐标 );
SetViewportOrgEx(hdc,cx/2,cy/2,NULL);
– SetWindowOrgExBOOL SetWindowOrgEx(
HDC hdc, // 设备描述表句柄 int X, // 使用逻辑单位,窗口原点的 X 坐标值 int Y, // 使用逻辑单位,窗口原点的 Y 坐标值 LPPOINT lpPoint // 指向 POINT 结构变量,存
放原始的窗口原点坐标 )• SetWindowOrgEx(hdc,-cx/2,-cy/2,NULL);
1. 设置映射方式 MM_ANISOTROPIC , MM_ISOTROPIC (做适当调整)2. 设置窗口限度
SetWindowExt()BOOL SetWindowExtEx( HDC hdc, // 设备描述表句柄 int nXExtent, // 新设置的水平方向窗口限度 int nYExtent, // 新设置的垂直方向窗口限度 LPSIZE lpSize // 原始窗口限度);
任意逻辑坐标系的设置
3. 设置视口限度BOOL SetViewportExtEx(
HDC hdc, // 设备描述表句柄 int nXExtent, // 新设置的水平方向视口限度 int nYExtent, // 新设置的垂直方向视口限度 LPSIZE lpSize // 原始视口限度);
坐标系的转换1. DPToLP()2. LPToDP()3. ClientToScreen()4. ScreenToClient()
3.8 使用 CDC 类绘制图形• 绘制点和线
– COLORREF SetPixel( POINT point, COLORREF crColor );
– CPoint MoveTo( POINT point );– BOOL LineTo( POINT point );
– BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
– BOOL AngleArc( int x, int y, int nRadius, float fStartAngle, float fSweepAngle );
– BOOL Polyline( LPPOINT lpPoints, int nCount );
– BOOL PolyPolyline( const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount );
– BOOL PolyBezier( const POINT* lpPoints, int nCount );
• 绘制封闭图形– BOOL Ellipse( LPCRECT lpRect );– BOOL Rectangle( LPCRECT lpRect )– BOOL RoundRect( LPCRECT lpRect, POIN
T point );– BOOL Pie( LPCRECT lpRect, POINT ptStar
t, POINT ptEnd );– BOOL Polygon( LPPOINT lpPoints, int nC
ount );– BOOL PolyPolygon( LPPOINT lpPoints, LP
INT lpPolyCounts, int nCount );
• CPen 类和画笔
函数原型 说明CPen( ); 构造 Cpen对象CPen( int nPenStyle, int nWidth,COLORREF crColor );
构造 Cpen对象,并创建样式为 nPenStyle,宽度为 nWidth,颜色为 crColor的 GDI画笔对象
BOOL CreatePen( int nPenStyle, int nWidth,COLORREF crColor );
并创建样式为 nPenStyle,宽度为 nWidth,颜色为 crColor的 GDI画笔对象
BOOL CreatePenIndirect( LPLOGPENlpLogPen );
创建 GDI 画笔对象,参数为 lpLogPen 指向 LOGPEN结构对象。
LOGPEN结构的定义如下:typedef struct tagLOGPEN { /* lgpn */ UINT lopnStyle; //画笔样式 POINT lopnWidth; //画笔宽度 COLORREF lopnColor; //画笔颜色} LOGPEN;
样式 线形PS_SOLID
PS_DASH
PS_DOT
PS_DASHDOT
PS_DASHDOTDOT
PS_NULL
PS_INSIDEFRAME
(1) 调用带参数的构造函数创建 GDI 画笔对象,例如: Cpen m_Pen (PS_SOLID,1,RGB(0,0,255));
(2)先调用缺省构造函数创建 CPen 对象,然后调用 Indirect 函数创建 GDI 画笔对象,例如:
Cpen m_Pen;
LOGPEN logpen ; logpen .lopnStyle=PS_SOLID; // 画笔样式 logpen .lopnWidth=1; // 画笔宽度 logpen .lopnColor=RGB(0,0,255);
m_Pen. CreatePenIndirect(&logpen );
• 1 . 画刷和 CBrush 类函数原型 说明CBrush( ); 构造 CBrush对象CBrush( COLORREF crColor ); 构造 CBrush 对象,并创建实心画刷,颜
色由参数 crColor指定CBrush( int nIndex, COLORREF crColor ); 构造 CBrush 对象,并创建阴影线画刷,
阴影线样式由 nIndex指定,颜色由 crColor指定
CBrush( CBitmap* pBitmap ); 构造 CBrush 对象,并创建位图画刷,位图由 pBitmap指定
BOOL CreateSolidBrush( COLORREFcrColor );
创建实心画刷,颜色由参数 crColor指定
BOOL CreateHatchBrush( int nIndex,COLORREF crColor );
创建阴影线画刷,阴影线样式由 nIndex指定,颜色由 crColor指定
BOOL CreateBrushIndirect( constLOGBRUSH* lpLogBrush );
创建画刷,画刷类型由 lpLogBrush 指向的 LOGBRUSH结构变量指定
BOOL CreatePatternBrush( CBitmap*pBitmap );
创建位图画刷,位图由 pBitmap指定
LOGBRUSH 的结构定义如下:typedef struct tagLOGBRUSH { // lb
UINT lbStyle;
COLORREF lbColor;
LONG lbHatch;
} LOGBRUSH; LbStyle 画刷类型BS_HATCHED 阴影线画刷BS_HOLLOW, BS_NULL 空心画刷BS_PATTERN,BS_PATTERN8X8 位图画刷BS_SOLID 实心画刷
样式 阴影线图式HS_HORIZONTAL
HS_VERTICAL
HS_FDIAGONAL
HS_BDIAGONAL
HS_CROSS
HS_DIAGCROSS
阴影线的样式:
( 1 )创建实心画刷使用带参数的构造函数创建CBrush brush(RGB(255,0,0));
先使用缺省的构造函数创建 Cbrush 对象,然后调用成员函数创建画刷
CBrush brush ; brush.CreateSolidBrush(RGB(255,0,0))
( 2 ) 创建阴影线画刷使用带参数的构造函数创建,例如 :
CBrush brush(HS_DIAGCROSS,RGB(0,255,0));
先使用缺省的构造函数创建 Cbrush 对象,然后调用成员函数创建画刷。如:
CBrush brush;
brush.CresteHatchBrush(HS_DIAGCROSS,RGB(0,255,0));
( 3 )创建位图画刷– 准备一个位图对象
• CBitmap bitmap ;• bitmap.LoadBitmap(IDB_BITMAP1);
– 使用 CBrush 类带参数的构造函数创建位图画刷,例如 :
• CBrush brush(&bitmap);
– 先使用缺省的构造函数创建 Cbrush 对象,然后调用成员函数创建画刷。例如:
• CBrush brush;• brush.CrestePatternBrush(&bitmap);
1 . TextOut 2 . DrawText-- 在指定矩形区域以一定格式输出字符串
DT_BOTTOM DT_CENTERDT_LEFT DT_RIGHTDT_SINGLELINEDT_TOPDT_VCENTER …
3.9 使用 CDC 成员函数绘制文本 文本输出函数
3. ExtTextOut• 函数功能:在指定位置输出字符串,并且在文本周围给矩形填充背景色。
• 函数原型: BOOL ExtTextOut( int x, int y, UINT nOptions, LPCRECT lpRect, const CString& str, LPINT lpDxWidths );
参数 说明x,y 字符串输出起始位置 x,y坐标NOpti ons 指定矩形框的样式;如果设置为 ETO_CLI PPED则字符串被矩形框剪切,
如果设置为 ETO_OPAQUE则矩形框将被背景色填充。LpRect 指定矩形,可以设置为 NULL。Str 绘制的字符串LpDxWi dths
指向一个数组;数组元素 i 的值决定了第 I 个字符与第 I +1个字符的间隔距离;可以设置为 NULL。
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetBkColor(RGB(0,255,0));
CRect rect(0,0,200,40);
int array[5]={40,25,35,45,15};
dc.ExtTextOut(10,10,ETO_CLIPPED|ETO_OPAQUE,&rect,CString("hello"),array);
}
4.TabbedTextOut 函数• 函数功能:和 TextOut() 的差不多,只是它支持制表符,定义一组制表符的位置。
• 函数原型: CSize TabbedTextOut( int x, int y, const CString& str,
• int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin );
参数 说明x,y 字符串输出起始位置 x,y坐标Str 绘制的字符串NTabPosi ti ons 指定制表符的个数LpnTabStopPosi ti ons 指向一个存放制表符位置的数组NTabOri gi n 制表符的扩展宽度
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
int array[3]={80,140,200};
dc.TabbedTextOut(0,0,CString("hello\thow\tare\tyou"),0,NULL,0);
dc.TextOut(0,180,CString("hello\thow\tare\tyou"));
}
1. SetTextAlignTA_BASELINE
TA_BOTTOM
TA_TOP
TA_CENTER
TA_LEFT
TA_RIGHT …
文本格式控制
2. SetTextCharacterExtra• 函数功能:设置字符间距• 函数原型: int SetTextCharacterExtra(
int nCharExtra );•参数说明: nCharExtra为添加的空白数
(逻辑单位)
3. SetTextJustification• 函数功能 : 设置词间距• 函数原型: int SetTextJustification( int nB
reakExtra, int nBreakCount );
•参数说明: nBreakExtra 为所有空格添加的空白数(逻辑单位); nBreakCount 为一行字符串中的空格数。
GetTextExtent 函数• 函数原型: CSize GetTextExtent( const C
String& str )
• 函数功能: 返回输出字符串 str 所占用的显示空间(逻辑单位)
void CChildView::OnPaint()
{
CPaintDC dc(this); dc.SetTextAlign(TA_RIGHT);
dc.TextOut(100,20,CString("right aligned"));
dc.SetTextAlign(TA_LEFT);
dc.TextOut(100,60,CString("left aligned"));
int oldextra=dc.SetTextCharacterExtra(5);
dc.TextOut(100,100,CString("left aligned and add 5 extra"));
CSize size=dc.GetTextExtent(CString("left aligned and add 5 extra and justified"));
CRect rect;
GetClientRect(&rect);
dc.SetTextJustification(rect.Width()-size.cx,7);
dc.TextOut(0,140,CString("left aligned and add 5 extra and justified"));
dc.SetTextCharacterExtra(oldextra);
dc.SetTextJustification(0,0);
dc.TextOut(100,180,CString("left aligned"));
}
3.6.3 获取文本尺寸
1.GetTextMetrics2.GetTextExtentPoint
typedef struct tagTEXTMETRIC
{ LONG tmHeight; LONG tmAscent; LONG tmDescent; LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight; … } TEXTMETRIC;
设置字符和背景颜色
(1)SetTextColor 函数(2)SetBKColor 函数
CFont 类与字体• Windows 字体
– 栅格型 (Raster)– 矢量型 (Vector)– TrueType
• 字体要素– 字型(字体名称)– 字型样式(字体样式)– 大小(从低端到顶端的距离)
成员类型
成员名 使用说明
LONG l fHei ght 字符高度(使用逻辑单位)设置为 0时,使用缺省高度
LONG l fWi dth 字符平均宽度, 设置为 0时,使用匹配宽度LONG l fEscapement 字符与 X轴的角度,缺省为 0LONG l fOri entati on 字符排列角度,值为角度*10,如 900代表 90度,
1800为逆向LONG l fWei ght 字符中线的粗细度, 取值范围:
FW_DONTCARE, FW_THI N, …FW_NORMAL, FW_REGULAR….FW_BOLD, . . FW_BLACK, FW_HEAVY
BYTE l f I tal i c 非 0为斜体BYTE l fUnderl i ne 非 0为加下划底线BYTE l fStri keOut 非 0为在字符中央加线
BYTE l fCharSet 字符集,可以设置以下字符集:ANSI _CHARSET,DEFAULT_CHARSET,SYMBOL_CHARSET,SHI FTJ I S_CHARSET,HANGUL_CHARSET,GB2312_CHARSET,…
BYTE l fOutPreci si on 精确度: OUT_DEFAULT_PRECI S,OUT_DEVI CE_PRECI S, (devi ce)OUT_RASTER_PRECI S, (Raser)OUT_TT_ONLY_PRECI S(onl y true type)OUT_TT_PRECI S(true type)
BYTE l fCl i pPreci si on 裁剪字符的方法: CLI P_DEFAULT_PRECI SBYTE l fQual i ty 字体质量: DEFAULT_QUALI TY
DRAFT_QUALI TY, PROOF_QUALI TYBYTE l fPi tchAndFami l y 宽度种类与字体家族,可以设置以下值:
宽度种类: DEFAULT_PI TCH,VARI ABLE_PI TCH, FI XED_PI TCH字体家族:FF_DECORATI VE(Ol d Engl i sh),FF_DONTCARE,FF_MODERN(Couri er New),FF_ROMAN(Ti mesNewRoman),FF_SCRI PT(Scri pt),FF_SWI SS(Ari al)
TCHAR l fFaceName[LF_FACESIZE]
字体名称
获取字体尺寸信息• GetTextMetrics 函数• BOOL GetTextMetrics ( LPTEXTMETRI
C lptm )
typedef struct tagTEXTMETRIC
{ int tmHeight;
int tmAscent;
int tmDescent;
int tmInternalLeading;
int tmExternalLeading;
int tmAveCharWidth;
int tmMaxCharWidth;
int tmWeight;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmFirstChar;
BYTE tmLastChar;
BYTE tmDefaultChar;
BYTE tmBreakChar;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
int tmOverhang;
int tmDigitizedAspectX;
int tmDigitizedAspectY;
} TEXTMETRIC;
使用 CFont 类创建字体• 构造 CFont 对象• 调用成员函数创建字体对象
– CreateFontIndirect 函数• 函数原型: BOOL CreateFontIndirect(const L
OGFONT* lpLogFont );•参数说明: lpLogFont 就是 LOGFONT 的指针
类型。
– (2)CreateFont 函数• 函数原型: BOOL CreateFont( int nHeight, in
t nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename );
– (3)CreatePointFont 函数• 函数原型: BOOL CreatePointFont( i
nt nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL );
void CChildView::OnPaint()
{ CPaintDC dc(this);
CString fontname[5]={“宋体” ,”隶书” ,”仿宋体” ,”楷书” ,”黑体” } ;LOGFONT flog;
ZeroMemory(&flog,sizeof(flog));
flog.lfHeight=48;
flog.lfWeight=FW_BOLD;
flog.lfCharSet=GB2312_CHARSET;
for(int i=0;i<5;i++)
{ strcpy(flog.lfFaceName,fontname[i]);
CFont font;
font.CreateFontIndirect(&flog);
dc.SelectObject(&font);
dc.TextOut(20,20+i*48,fontname[I];
}
}
本章重点及编程要求:
1 . 绘图的基本步骤2 . 设备环境的获取与使用3 . GDI 对象的使用5 . 逻辑坐标的设 置