南希系列中就用到了GDI+编程 9 q% h- e6 x% O5 ]. e
1 I. x3 L* L$ f字体是文字显示和打印的外观形式,它包括了文字的字样、风格和尺寸等多方面的属性。适当地选用不同的字体,可以大大地丰富文字的外在表现力。例如,把文字中某些重要的字句用较粗的字体显示,能够体现出突出、强调的意图。当然,文本输出时还可使用其格式化属性和显示质量来优化文本显示的效果。
% k- P9 j6 a" p1 `$ d: }6 _: q& J5 [
字体属性和字体创建
. W1 ?. P5 i4 f; F" `# A* \# z1 i7 s# I. @$ f% H
字体的属性有很多,这里主要介绍字样、风格和尺寸三个主要属性。 + Q ^: n% E% ~, [( ^' y$ l S
( W5 o, T& r2 N/ u' m 字样是字符书写和显示时表现出的特定模式,例如,对于汉字,通常有宋体、楷体、仿宋、黑体、隶书以及幼圆等多种字样。GDI+是通过FontFamily类来定义字样的,例如下面的代码: 6 e7 x2 j8 S/ e/ h% Q! d
6 S8 e: t. S; h( J: kFontFamily fontFamily(L"幼圆"); // 定义"幼圆"字样
6 }# n5 J3 z4 Q/ I; s, d# v) \3 i. i' b9 v# q2 }
字体风格主要表现为字体的粗细和是否倾斜等特点。GDI+为用户提供了一些预定义的字体风格:FontStyleRegular(正常)、FontStyleBold(加粗)、FontStyleItalic(斜体)、FontStyleBoldItalic (粗斜体)、FontStyleUnderline(下划线)和FontStyleStrikeout(删除线)。 6 i& `- t6 h! }, k: _9 Q
4 D3 i/ H6 o- g0 p/ |# Z$ {9 M 字体尺寸是用来指定字符所占区域的大小,通常用字符高度来描述。字体尺寸可以取毫米或英寸作为单位,但为了直观起见,也常常采用一种称为点的单位,一点约折合为1/72英寸。对于汉字,还常用号数来表示字体尺寸,初号字最大,以下依次为小初、一号、小一、二号、小二??,如此类推,字体尺寸起来越小。GDI+为用户提供了UnitDisplay(1/75英寸)、UnitPixel(像素)、UnitPoint(点)、UnitInch(英寸)、UnitDocument(1/300英寸)、UnitMillimeter(毫米)等字体尺寸单位。 4 g( m5 _" R' {3 m; A* y
: L) E' n6 J& [6 ?6 Z* t 使用GDI+中的Font类,可以直接通过构造函数创建一个字体对象,例如下列代码:
# O c- B7 H( d2 r* w
; q$ z1 O( k3 V; C! aFont font(&fontFamily, 12, FontStyleRegular, UnitPoint); $ o( Y! L5 P Y# U& _. f5 y
, N3 T2 T2 a: _9 X2 o6 r1 Z7 Z
构造函数的第一个参数是用来指定FontFamily类对象指针,第二参数是用来指定字体的尺寸,它的实际大小取决于第四个参数所指定的尺寸单位。第三个参数用来指定字体风格。
. N0 S1 J: k( U0 Y, c- K/ {4 J# B+ ^4 S7 |% N$ r/ _2 T# Y
为了与原来的GDI字体相兼容,Font的构造函数还有另外一种型式:
5 v2 b7 P u4 ^2 p3 g' d0 ~, E6 O5 w9 X* |. s8 I: j+ \
Font( HDC hdc, const LOGFONTW* logfont)
2 r0 y- W u- `- P$ Z. l0 p6 A5 p$ y& {- Z. a2 C
其中,hdc是用来指定一个窗口的设备环境句柄,logfon是指向LOGFONT(逻辑字体)数据结构的指针。
7 z! \" n- @6 S; U
6 \2 s$ [5 q* B8 C+ e# Q文本输出
- V3 d% T+ _# I( t S' G- @- r5 F7 k' r6 _- B
文本的最终输出不仅依赖于文本的字体,而且还跟文本的颜色、对齐方式、字符间隔等有很大关系。GDI+只有一个输出文本的函数DrawString,它的原型如下: 4 F+ O8 }% \) U4 [) `
2 p: P$ M& X4 w6 }- q4 j" J- y
0 I' F" m0 Z6 l" G: M, T8 _* @4 g k3 M5 o" q- k- m1 j, x& Z
DrawString( const WCHAR* string, INT length, const Font* font, ; |; r% m. A) {) y$ I% H
const RectF& layoutRect, const StringFormat* stringFormat, 9 j7 ~: _" E5 }7 r' s& O' a
const Brush* brush );
# r2 ?% x: w+ C, H2 m& a+ Q* w) s R$ Z$ T5 x" `+ R
DrawString( const WCHAR* string, INT length, const Font* font,
8 H: W3 B% [" M. i* G- }! ^1 bconst PointF& origin, const Brush* brush ); 6 j8 `1 @% l% d/ { `" }/ u+ I
5 A+ ]2 f3 ^# y) e: J% t2 t$ _DrawString( const WCHAR* string, INT length, const Font* font,
* J& Z7 g5 j7 p l: [* f9 r1 Bconst PointF& origin, const StringFormat* stringFormat,
5 x- z7 j; h% E3 [const Brush* brush);
* M$ n" M4 c* {+ T, K# f
' U, x7 {) t- |: I ^) Z. e& e* Z; K4 H; X- `# d5 s
+ M* f: ^! g- H1 ^) a% H& G: D
其中,string用来指定要输出的字符串,length表示该字符串的长度,font用来指定字体,layoutRect用来指定一个字符串所输出的矩形区域,stringFormat用来指定文本输出格式化属性,origin用来指定字符串输出的起点。需要注意的是,PointF和RectF类与Point和Rect类基本相同,所不同的是数据类型是浮点而后者是INT型。brush用来指定一个画刷,这个画刷既可以是SolidBrush和HatchBrush,也可以是TextureBrush(纹理画刷),甚至是渐变画刷。例如下面的代码,结果如图7.14所示。 7 I$ E0 C& f7 s& R$ q/ n
: m. z* Q# P, t4 F4 y* xGraphics graphics( pDC->m_hDC ); : k4 _! `& k/ I/ H
' d. h' H& }/ H- n; E8 RFontFamily fontFamily(L"幼圆");
/ Z; T0 ^0 Z/ V8 ?& cFont font(&fontFamily, 20, FontStyleRegular, UnitPoint); y- o5 i+ S# r2 ~
PointF pointF(30, 10); " ?+ v# f4 u6 V! v: Y e7 H! E* z
Image image(L"image.jpg"); 2 F* L. h4 W s6 M8 V- D
TextureBrush tBrush(&image);
; |( X+ i) L0 f* Y1 j9 \ M- ^, |, \1 E# P0 l7 w* f f+ D
LinearGradientBrush linGrBrush(
6 g7 A: s9 n8 i' G, [0 |Point(30, 50),
. u/ ~1 ^& F# f' pPoint(100, 50), ) Z" m- M8 E+ X
Color(255, 255, 0, 0),
6 X! q9 I2 G+ [( E2 v9 o1 Q0 WColor(255, 0, 0, 255)); 0 L" m: V% {) B! X
" ^3 h$ {4 n! I+ ?WCHAR string[256]; : Q5 @4 m7 a1 R8 W% L4 B) X7 ^3 Z, G
wcscpy(string, L"欢迎使用GDI+!"); . F1 B! z9 ?; Q
" a$ t$ u9 r; n% ^ {6 O( G! `graphics.DrawString(string, (INT)wcslen(string), &font, pointF, &tBrush);
: W. h c) ]" ^. r$ \. ?pointF.Y += 50; $ T5 u5 R5 I3 k
graphics.DrawString(string, (INT)wcslen(string), &font, pointF,
8 h5 |5 M! m* W# y* \; p- y5 P&linGrBrush); * {. V u( _5 |1 s
. G* f+ W' K& x/ h$ e 需要说明的是,在GDI+中,我们可以通过SetTextRenderingHint来控制文本输出的质量。例如下面的代码,其结果如图7.15所示。 9 m4 v1 { ^2 g2 Z5 m% q
4 }* S7 e1 @$ f- R0 U$ W
Graphics graphics( pDC->m_hDC ); v( y4 y& M0 e" s+ h
3 ]+ `( R9 m* S
FontFamily fontFamily(L"楷体_GB2312");
8 D' U+ m K8 A. GFont font(&fontFamily, 30, FontStyleRegular, UnitPixel);
! R+ k. b0 Z9 p( _ ^6 x0 \& uSolidBrush solidBrush(Color(255, 0, 0, 255));
5 @: l! y7 ^ M1 [3 l; rWCHAR string1[] = L"没有任何优化处理";
' C6 t+ X, D7 k8 t8 HWCHAR string2[] = L"字体优化,但边不作平滑处理";
" q2 r' o, T/ o# N1 a" n/ j. bWCHAR string3[] = L"消除走样,且边作平滑处理"; ) O4 t! X- |1 I2 ~/ w& E
- _) ?# i7 c+ s8 |graphics.SetTextRenderingHint(TextRenderingHintSingleBitPerPixel);
# c3 S2 |$ j3 x7 agraphics.DrawString(
$ I* y8 m; a6 b; ^/ f2 jstring1, (INT)wcslen(string1), &font, PointF(10, 10), &solidBrush);
4 i; X6 W7 D( ^9 a8 \, J0 i, V) ^; @
graphics.SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit);
4 @8 R1 X1 h6 R u3 I6 ^- F4 zgraphics.DrawString(
; L; A7 `* h U1 F2 Q9 B. Dstring2, (INT)wcslen(string2), &font, PointF(10, 50), &solidBrush);
% p- a" e1 m0 x. }" Z% u6 ]2 p v# G9 g$ z3 i g% |
graphics.SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
/ ]* X7 W' g" Lgraphics.DrawString( ) s9 s9 c9 Q; [0 t; e
string3, (INT)wcslen(string3), &font, PointF(10, 90), &solidBrush);
7 d. @( r7 i! e
o5 u( g; `1 m& \* j
, m% z4 g4 }3 b2 e. c8 r, s
( U {- _: O1 O$ x; W' s文本格式化属性 3 ]1 C! m+ X7 u6 ]7 [ b' w2 _( S$ L
L5 E8 g2 x& }; O; f5 [. o 文本的格式属性通常包括对齐方式、字符间隔以及文本调整等。GDI+提供StringFormat类来控制这些格式属性,通常我们调用以下几个函数来进行相关属性设置。
4 K7 b" ]; N% Z# r+ b$ s2 y
( V" c! v6 c5 d* `. cStatus SetAlignment( StringAlignment align);
& R# j B a2 sStatus SetLineAlignment( StringAlignment align);
8 i. b* Z; ~4 U5 r- a( o5 z3 h9 ?, E8 y) I1 Z
该函数用来设置文本对齐方式,align可以是StringAlignmentNear(左对齐或右对齐,取决于书写方向是从左到右还是从右到左)、StringAlignmentCenter(居中)或StringAlignmentFar(两端对齐)。
2 d2 `% V8 \" H N
/ y/ {6 a- G: S! a% j/ X5 m8 AStatus SetFormatFlags( INT flags ); 5 ?, l) W4 y0 o* V z0 M- @9 ?
4 x7 |8 r7 y) d: l
该函数用来设置文本格式化标志,flags可以是StringFormatFlagsDirectionRightToLeft(水平阅读方向是从右向左)和StringFormatFlagsDirectionVertical(垂直文本)等值。例如下面的代码,其结果如图7.16所示。 ; N. u; x' L5 z- t3 b
9 A% {9 C, a [0 d: N% R2 Z
Graphics graphics( pDC->m_hDC );
& B) ~- O6 {& x3 {& t5 L& E7 ESolidBrush solidBrush(Color::Blue); Q5 K: A' t% o, [: K. F' y2 i
FontFamily fontFamily(L"楷体_GB2312"); ( Q- v6 O1 l: \ w- w6 K- K
Font font(&fontFamily, 16, FontStyleRegular, UnitPoint);
" B% c2 x0 B& E3 h8 E: Z; j
* s$ x7 q4 s ZStringFormat stringFormat;
2 n& k& n ]% u& c* _ z; ]- pstringFormat.SetFormatFlags( StringFormatFlagsDirectionRightToLeft |
: ] |3 E/ ?4 h8 _% c- EStringFormatFlagsDirectionVertical |
' o! o+ W' ~8 P' j' ~" q9 vStringFormatFlagsNoFitBlackBox);
; T. g- I( B; x0 LstringFormat.SetAlignment(StringAlignmentCenter);
. ^3 k2 e" ^. i' l# A+ }. n' X$ TWCHAR string[] = L"这些文字是垂直居中且是从右到左的阅读次序, 它们是通过 \ - M6 P' [9 c1 I( ^; w
SetFormatFlags和SetAlignment来设置的!"; ! z7 I5 X5 j. F; G' X9 I9 T
. E4 g" ?* F/ f: w/ Y
graphics.DrawString( string, (INT)wcslen(string), &font, 8 ^) b, j( j5 \' k& n+ y' i
RectF(30, 30, 150, 200), &stringFormat, &solidBrush); |