📄 05.3 路径.txt
字号:
5.3 路径
在设备描述表中还有一个路径层 ( path bracket )的概念。什么是路径层呢?路径层的概念就像当年军阀割据时圈地那样,在地域上划定了界线,界线之内的是各自的地盘,别人不能侵犯。
在 MFC中,创建路径层是利用 CDC类提供的 BeginPath和 EndPath这两个函数来实现的,首先应调用前者,该函数的作用是在设备描述表中打开一个路径层 :然后利用图形设备接口 ( GDO提供的绘图函数进行绘图操作,例如绘制一些点、矩形、椭圆等:最后,在绘图操作完成之后,应用程序通过调用 E ndPath函数关闭这个路径层。
下面我们在路径层中绘制一个矩形,将先前输出的 "vc++深入编程"字符串框起来。如果要用一个矩形把字符串框起来,就需要知道这个字符串在窗口中的坐标值。在上述例子6所示代码中,字符串 " vc++深入编程"是在坐标。0, 5 0)处输出的,于是我们可以确定矩形的左上角坐标为 ( 50,50 ),但是如何确定矩形的右下角坐标呢?对一个字符串来说,如果能够知道它的宽度和高度,再加上它的左上角坐标就能够得到包围这个字符串的矩形的右下角坐标了。我们能不能利用 C语言中的 strlen函数来获得字符串的宽度呢?要注意, s trlen这个函数获得的是字符串中字符的个数,而字符串在窗口中显示时占据的宽度并不是由其字符数来决定的。例如 " w "和 " i ",同样是一个字符,但它们所占据的宽度是不一样的。同时,字体的大小也会影响字符串在窗口中显示的宽度。另外,我们在使用 Word
时,经常会根据需要调整宇间距,也就是说,字符和字符之间实际上是有间距的。由此可见,一个字符串在屏幕上显示的宽度是由多个方面的因素决定的,因此,希望利用 strlen函数来获得字符串的宽度是根本无法做到的。 CDC类为我们提供了一个 GetTextEx tent函数,利用这个函数可以获得一个字符串在屏幕上显示的宽度和高度,这个函数的一种声明形式如下所示 :
CSize GetTextExtent( const CStr工 ng& str ) const;
从上述声明可以得知,我们需要给这个函数传递一个字符串,它会返回一个 CSize类
型的对象。 CSize类类似于 Windows的 SIZE结构体。后者的定义如下所示 :
typedef struct tagSIZE {
int cx;
lnt cy;
} S工 ZE ;
该结构体有两个成员变量 : cx和 cy.分别表示宽度和高度。
GetTextEx tent函数需要一个 CS tring对象的引用作为其参数,前面刚刚说过,不同的字符在窗口中显示时,其宽度可能也是不同的,因此,想要得到字符串在窗口中的显示宽度,必须针对特定的字符串调用 GetTextExtent函数。不要把这个函数和前面讲过的 GetTextMetrics函数混淆了,对GetTextMetrics函数来说,它获得的是设备描述表中当前字 体的度量信息。而 GetTextExtent函数则是获得某个特定的字符串在窗口中显示时所占据的宽度和高度。读者一定要注意区分这两个函数的作用。
例 5-8所示代码是使用路径层的具体实现代码。
例 5-8
1 . void CTextView: : OnDraw(CDC* pDC)
2. {
3. CTextDoc* pDoc = GetDocument() ;
4. ASSERT_VALID(pDoc);
5. 11 TODO : add draw code for native data here
6 . //CString s tr ( "VC++ 深入编程" ) ;
7. CString str;
8. str = "VC++ 深入编程··;
9. pDC->TextOut(50 , 50 , str);
10. CSize sz = pDC->GetTextExtent(str);
11. str. LoadString(IDS_ STRINGVC) ;
12 . pDC->TextOut:. (0 , 200 , s t:. r) ;
13 . pDC->BeginPath() ;
14. pDC->Rectangle(50 , 50 , 50+sz . cx, 50+sz . cy);
15. pDC->EndPath();
16. }
146 I
请读者考虑一下,如果将上述例 5-8所示代码中的第 10行代码放到第 11行之后,是否可以?
Bui1d井运行 Text程序,读者将会发现程序窗口与前面的程序结果没有什么不同。但是当我们把上述代码中打开和关闭路径层的两行代码(第 13行和第 15行)注释起来,也
就是不在路径中绘制矩形, 看看程序运行结果会是怎样的。 这时的程序运行界面如图 5.13
所示。
图 5.13不在路径中绘制矩形的程序效果
前面己经讲过,设备描述表中有一个默认的白色画刷,当绘制矩形时,它会用这个画刷来填充矩形内部,因此本例中,调用 Rectang1e函数后,就把先前绘制的文字给覆盖了。前面我们已经看到,如果是在路径层中绘制矩形,那么它对先前输出的文字是没有影响的。既然没有影响,那么路径层有什么作用呢?
下面我们先在窗口中绘制一些网格状线条,这些线条将覆盖己输出的文字。具体代码如例 5 -9所示。
1;IJ 5-9
void CTextView:: OnDraw(CDC* pDC) {
CTextDoc * pDoc二 GetDocument() ;
ASSERT_VALID(pDoc) ;
// TODO : add draw code for native data here
/ / CString str ( "VC++ 深入编程 11 ) ;
CString str;
str =叮C++深入编程 ";
pDC->TextOut(50 , 50 , str) ;
CSize sz = pDC->GetTextExtent(str) ;
str . LoadString(工 DS_STRINGVC) ;
pDC->TextOut(O , 200 , str) ;
pDC->Be ginPath() ;
pDC->Rectangle(50 , 50 , 50+sz . cx, 50+sz . cy) ;
pDC->EndPath() ;
~~~ I 147
第5
for(int i=O;土<300; i+=lO)
pDC->MoveTo(O , i);
pDC->LineTo(300 , i);
pDC->MoveTo(i , O);
pDC->LineTo(i , 300);
上述例5-9所示代码中利用一个循环来实现网格状线条的绘制,线条与线条之间的间距为 10个逻辑单位。在这个循环中,首先是纵坐标不断变化,绘制网格的横线;接着是横坐标不断变化,绘制网格的坚线。
Build井运行Text程序,结果如图5.14所示,我Jd鼠忌 T(>)(t 切··们发现多了些网格线把先前输出的文字遮盖住了。此时,我们还是没有看出路径层到底有什么好处。
这里,先介绍一下裁剪区域 (clipping region) 的概念。可以把它理解为一个绘图区域,其大小可以由我们来控制。我们知道对单文档应用程序来说,除了标题栏、菜单栏以外,剩余的就是客户区。通常可以把客户区看作一个大的裁剪区域,但裁剪区域也可以局限于客户区中一个很小的范围之内。例如,可以限制一个矩形区域作为裁剪区域,把以后的绘图操作嚣'仅限于这个矩形之内。
CDC类提供了一个SelectClipPath函数,该函数 图 5.14加了网格线的效果
的作用是把当前设置的路径层和设备描述表中己有的裁剪区域按照一种指定的模式进行一个互操作。该函数的声明形式如下所示:
BOOL SelectClipPath( int nMode );
其中,参数nMode用来指定互操作的模式,它可以有多种取值,例如RGN_DIFF,该
模式的含义是新的裁剪区域包含当前裁剪区域,但排除当前路径层区域。我们可以看看这
个模式产生的效果。修改上述例5-9的代码,在EndPath函数调用之后,添加SelectClipPath函数的调用,结果如例子10所示。
例5-10
void CTex tView: :OnDraw(CDC* pDC)
CTextDoc* pDoc = GetDocument() ;
ASSERT_VALID(pDOC) ; /1 TODO : add draw code for native data here /ICStri ng str("vC++ 深入编程" ) ;
CSt ring st r;
str =叮C++深入编程";
148 I ~~~
pDC->TextOut(50 , 50 , str);
CSize sz = pDC->GetTextExtent(str);
str. LoadString(IDS_STRINGVC) ; pDC->TextOut(O , 200 , str);
pDC->BeginPath() ;
pDC->Rectangle(50 , 50 , 50+sz . cx, 50+sz . cy) ;
pDC->EndPath() ;
pDC->SelectClipPath(RGN_D工FF) ;
for(int i=O ; i<300 ; i+=10)
pDC->MoveTo(O,工) ;
pDC->L工neTo (300,工) ;
pDC->MoveTo(i , 0) ;
pDC->LineTo(i , 300) ;
Build并运行Text程序,程序结果如图5.15所示。可以发现窗口中绘制的线条到了程序设置的矩形路径部分就断开了。这正是RGN_DIFF模式的效果,它使新的裁剪区域包含了当前裁剪区域,但把当前路径层的范围排除在外。因此,在程序窗口中就看不到有线条穿过路径范围内的文字,到了这个路径范围线条就终止了。
我们再看看另一种裁剪区域操作模式: RGN J气ND的效果。该模式的作用是,新的裁剪区域是当前裁剪区域和当前路径层的交集。把上述例5-9所示代码中的裁剪区域操作模式(即加灰显示的那行代码中的参数: RGN_DIFF)换成RGN_AND,然后 Build并运行 Text程序,结果如图5.16所示。可以发现,这时只有矩形路径中显示的有线条,其他部分均没有线条。
li附 Ir,., '-l,
…
矗立志瞌踵
图5.15裁剪区域RGN_DIFF模式效果图 5.16裁剪区域RGN_AND模式效果
"‘ I 149
第 5文本罐雹
至此,读者应该看到路径层的作用了。以后在绘图时,就可以利用路径层这一特点来实现特殊的效果。例如,如果希望整幅图形中某一部分与其他部分有所区别,就可以把这部分的图形放置到一个路径层中,然后利用 SelectClipPath函数设置一种模式,让路径层和裁剪区域进行互操作以达到一种特殊的效果。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -