友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
C语言实例教程(PDF格式)-第44部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
程序与输出设备之间的中介,一方面,GDI向应用程序提供了一个设
备无关的编程环境,另一方面,它又以设备相关的格式和具体的设备
打交道。
经常同图形设备接口相提并论的另一个概念是设备上下文 (Device
Context,DC)。设备上下文是一种Windows数据结构,它包括了与一
个设备 (如显示器或打印机)的绘制属性相关的信息。所有的绘制操作
通过一个设备上下文对象进行,该对象封装了实现绘制线条、形状和
文本的Windows API函数。设备上下文可以用来向屏幕、打印机和图
元文件输出结果。
在Windows应用程序中,我们通常在绘制之前调用BeginPaint函数,
然后在设备上下文中进行一系列的绘制操作,最后调用EndPaint函数
结束绘制。MFC类CPaintDC封装了这一过程。在构造CPaintDC对象的
同时,其构造函数自动调用BeginPaint函数;在消毁CPaintDC对象的
同时,其析构函数自动调用EndPaint函数。因此前面所讲述的过程可
以对应于下面的三个步骤:构造一个CDC对象,进行绘制操作,消毁
该CDC对象。在基于文档/视结构的应用程序框架中,这个过程被进一
步的简化。回忆前几章中讲述的内容,我们一般在视类的OnDraw成员
函数中处理有关重绘的操作。通过OnPrepareDC成员函数,框架自动
的向OnDraw成员函数传递一个类型为CPaintDC的设备上下文对象。我
们只需简单的通过该对象进行绘制,而不需要关心这一对象的构造和
消毁。这一过程由框架自动的完成,而且,隐藏在背后的设备上下文
在对OnDraw的调用返回时由框架进行释放。
除了上面的CPaintDC类外,MFC还提供了其它的一些封装不同设备上
下文的类。如CClientDC类,它所封装的设备上下文仅代表了一个窗
口的客户区。在CClientDC的构造函数中调用的不是BeginPaint函
数,而是GetDC函数;相应的,ReleaseDC函数在类CClientDC的析构
函数被自动调用。与此对应的还有另一个类CWindowDC,它所封装的
设备上下文代表的是整个窗口,不仅包括其客户区,也同时包括窗口
的边框及其它非客户区对象。
所有的设备上下文类中比较特殊的是类CMetaFileDC,通过
…………………………………………………………Page 514……………………………………………………………
CMetaFileDC对象所进行的绘制操作不是对一个实在的设备来进行
的,这些操作都被记录到一个Windows图元文件中。不象自动传递给
OnDraw成员函数的CPaintDC对象,如果要在这种情况下使用
CMetaFileDC对象的话,我们必须自己调用OnPrepareDC成员函数。
所有的这些设备上下文类都以类CDC作为其基类。
一般情况下,很多绘制操作都是在应用程序的视类的OnDraw成员函数
中进行的,前面说到过,当视类窗口收到消息WM_PAINT时,该消息对
应的处理函数OnPaint被调用,该处理函数构造一个CPaintDC对象,
并将指向该对象的指针传递给OnDraw成员函数。这里我们考虑这样一
种情况,如果我们正在编写的是一个通过鼠标在屏幕上绘图的应用程
序。这时我很显然需要为鼠标的移动消息添加消息处理函数,而且,
我们希望用户在移动鼠标的过程中立即就可以看到所绘制的内容,而
不是等到窗口收到WM_PAINT消息(即发生重绘事件)才调用成员函数
OnDraw绘制窗口。在这种情况下,我们更倾向于直接在鼠标消息处理
函数中进行绘制,这时,就需要创建一个设备上下文对象,然后通过
该对象调用一系列的绘制方法。
Windows本身是一个图形界面的操作系统,进行Windows程序设计随时
都会同设备上下文打交道,甚至在本书前面的章节中的一些示例程序
中我们也已经用到了设备上下文,只不过在当时我们回避了与设备上
下文有关的很多复杂东西。本章的目的之一就是系统的讨论这些前面
已经用到但没有加以阐述的概念和技巧,并补充一些尚未涉及的内
容,这些内容包括:
l 使用设备上下文进行绘制
l 绘图对象
l 直线与曲线
l 填充形状
l 字体和文本
l 颜色
l 坐标空间及变换
这些概念往往是交织起来的,哪怕是一个很简单的绘制操作,往往都
需要用到不只一个绘图对象,因此我们很难将它们人为的分割开来进
…………………………………………………………Page 515……………………………………………………………
行讲述。在本章上,各节的标题只代表了本节的侧重点,而对于某一
个概念的叙述或使用,则有可能分散在不只一个小节中。事实上,一
个应用程序是一个整体,它常常需要很多个部件共同协调工作才可以
正常工作。因此,出现这种情况是很自然的。
第一节 设备上下文
在MFC应用程序中,绘制操作通常涉及三类对象,一类是输出对象,
亦即设备上下文对象,包括CDC及其派生类;一类是绘制工具对象,
亦即前面所说的图形对象,如果CFont、CBrush和CPen等;另一类属
于Windows编程中需要用到的的基本数据类型,如CPoint、CSize和
CRect等。
不同的设备上下文类封装了不同类型的设备上下文类对象,如表9。1
所示。
除了设备上下文以外,在Windows中进行绘制通常还需要各种绘制工
具,如用来绘制线条的笔、用来填充一个图形内部的刷子以及用来绘
制文本的字体等。这些工具称作图形对象,它们由Windows系统提
供,MFC提供的图形对象类对它们进行了封装,表9。2给出了这些图形
对象以及与它们等价的Windows图形设备句柄类型。
表9。 1 MFC中的设备上下文类
设备上下文 描述
类
CDC 所有设备上下文类的基类。可用来直接访问整个显
示器或如打印机之类的非显示设备上下文。
CPaintDC 在窗口的OnPaint成员函数中使用的一种显示上下
文。在其构造过程中自动调用BeginPaint,在其析
构过程中自动调用EndPaint。
CClientDC 代表窗口的客户区的显示上下文。通常在需要直接
在窗口客户区进行绘制时使用。
CWindowDC 代表整个窗口的显示上下文,包括客户区和非客户
区。
CMetaFileDC 代表Windows图元文件的设备上下文。一个Windows
图元文件包括一系列的图形设备接口命令,可以通
过重放这些命令来创建图形。向CMetaFileDC对象
进行的各种绘制操作可以被记录到一个图元文件
中。
…………………………………………………………Page 516……………………………………………………………
表9。 2 MFC 中的Windows GDI对象类
图形对象 等价的 描述
类 Windows图
形设备句柄
CBrush HBRUSH 用来填充正在绘制的对象的内部
CPen HPEN 用来绘制对象的边线
CFont HFONT 用来绘制文本
CBitmap HBITMAP 用来提供操作位图的接口
CPalette HPALETTE 用作应用程序和色彩输出设备(如显示
器)之间的接口
9。1。1 几个与图形绘制有关的简单数据类型
在讲述设备上下文和图形对象之前,我们来介绍几个常用的数据结构
类。
(1) CPoint类
CPoint类封装了一个点的坐标。它事实上是从POINT结构派生而来
的。结构POINT在Win32 SDK中定义。因此,CPoint也继承了POINT结
构的数据成员x和y。CPoint对象可以用在任何使用POINT结构的场
合。CPoint对象还可以和另一种简单数据类型CSize或SIZE结构相互
进行转换。
CPoint类具有多种形式的构造函数:
CPoint( );
CPoint( int initX; int initY );
CPoint( POINT initPt );
CPoint( SIZE initSize );
CPoint( DWORD dwPoint );
当使用DWORD类型的值来构造CPoint对象时,其低位字将被赋值给
…………………………………………………………Page 517……………………………………………………………
CPoint对象的成员x,高位字将被赋值给成员y。
CPoint的成员函数Offset可以设置点的偏移量,同时,在类中定义的
一些运算符,如?、?、??和??等大大的简化了对点坐标的各种运算和
比较。
(2) CSize类
如果要表示距离以及相对位置,可以使用CSize对象。MFC类CSize事
实上是从SIZE派生而来的,因此,CSize继承了SIZE结构的数据成员
cx和cy。构造一个CSize对象与用对应的方法构造CPoint对象非常相
似,因此我们不需讲述。同样,我们可以使用一个DWORD值来构造
CSize对象,这时,其低位字被赋值给CSize对象的成员cx ,高位字
被赋值给成员cy。在类Size中定义了六个运算符:?、?、?? 、?? 、??
和?? 。
(3) CRect类
CRect类是编程时经常使用的几个简单数据结构之一,它从RECT结构
派生,因此,CRect类继承了RECT结构的数据成员left、top、right
和bottom。它们是CRect的公有成员。
一个CRect对象可以传递给任何以RECT结构或LPCRECT和LPRECTW指针
为参数的函数。
l 注意:
l 在指定一个CRect对象时,一般情况下我们需要使它的左边界的坐
标小于右边界的坐标和上边界的坐标小于下边界的坐标。我们称
满足该条件的矩形为常态矩形。很多函数要求传递给它的CRect对
象表示一个常态矩形,否则这些函数将有可能返回一个错误的结
果。我们可以通过调用成员函数NormalizeRect来将一个非常态矩
形转换为一个常态矩形。在程序中出现非常态矩形并不一定的程
序员的疏忽大意。这里举一个例子,如果 当前显示上下文的映射
模式为MM_LOENGLISH,将一个表示常态矩形的CRect对象传递给成
员函数CDC::DPtoLP,将得到一个非常态矩形,该矩形的高度将成
为一个负值。这是因为在MM_LOENGLISH映射模式中,纵坐标的方
向是向上的。
相比我们在前面所讲述的CPoint类和CSize类来说,类CRect要庞大得
多。表列出了在类CRect中定义的成员函数。
…………………………………………………………Page 518……………………………………………………………
表9。 3 类CRect的成员函数
成员函数 描述
Width 计算矩形的宽度
Height 计算矩形的高度
Size 计算矩形的大小
续表9。3
成员函数 描述
TopLeft 返回矩形的左上角
BottomRight 返回矩形的右下角
CenterPoint 返回矩形的中点
IsRectEmpty 判断矩形是否为空。空的矩形的宽和高都为0
IsRectNull 判断矩形的top、bottom、left和right成员变
量是否全都为0
PtInRect 判断指定点是否的矩形内
SetRect 设置矩形的大小
SetRectEmpty 将矩形设置为空(所有坐标均为0)
CopyRect 从源矩形中拷贝维度到矩形中
EqualRect 判断两个矩形是否相等
InflateRect 扩大矩形的宽和高
DeflateRect 减小矩形的宽和高
NormalizeRect 使用矩形的宽和高标准化
OffsetRect 按指定的偏移量移动矩形
SubtractRect 从一个矩形中减去另一个矩形
IntersectRect 设置矩形为两个矩形的交
UnionRect 设置矩形为两个矩形的并
LPCRECT 转换CRect对象为LPCRECT
…………………………………………………………Page 519……………………………………………………………
LPRECT 转换CRect对象为LPRECT
= 拷贝一个矩形的维度到CRect对象
== 判断两个矩形的维度是否相等
!= 判断两个矩形是否不等
+= 将指定的偏移量添加到CRect对象或扩展CRect
对象
…= 从CRect对象中减去指定的偏移量或缩小CRect
对象
&= 设置CRect对象为CRect对象和另一矩形的交
|= 设置CRect对象为CRect对象和另一矩形的并
+ 将指定的偏移量添加到CRect对象或扩展CRect
对象,并返回一个CRect对象
从CRect对象减去指定的偏移量或缩小CRect对
象,并返回一个CRect对象
续表9。3
成员函数 描述
& 返回CRect对象和另一矩形的共同部分
| 返回CRect对象和另一矩形的并
9。1。2 显示设备上下文
对于在视类的OnDraw成员函数中使用设备上下文进行输出的这种情
况,我们已经以前面讲述文档和视时给出了一些示例,因此这里就不
再重复叙述,读者可以参考前面所讲述的内容。下面我们来看一下如
何自己构造设备上下文,并通过该设备上下文来进行绘制。
在示例程序MulticlrdCaption中,我们通过CWindowDC对象获得包括
客户区和非客户区的显示设备上下文,然后将窗口的标题绘制为五彩
的。
#include
#include
// 派生自己的应用程序类
…………………………………………………………Page 520……………………………………………………………
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
// 应用程序主窗口类
class CMyWnd : public CFrameWnd
{
protected:
void PaintTitleBar(BOOL bActive);
// 声明主窗口的消息处理函数
afx_msg void OnNcPaint();
afx_msg BOOL OnNcActivate(BOOL bActive);
DECLARE_MESSAGE_MAP();
};
// 初始化应用程序的实例
BOOL CMyApp::InitInstance()
{
// 创建应用程序主窗口
CMyWnd *pWnd=new CMyWnd;
pWnd…》Create(NULL; 〃具有五彩标题条的窗口〃);
// 显示应用程序主窗口,并更新客户区
pWnd…》ShowWindow(SW_SHOW);
pWnd…》UpdateWindow();
m_pMainWnd=pWnd;
return TRUE;
…………………………………………………………Page 521……………………………………………………………
}
// 声明应用程序对象
CMyApp MyApp;
// 应用程序主窗口的消息映射
BEGIN_MESSAGE_MAP(CMyWnd; CWnd)
ON_WM_NCPAINT()
ON_WM_NCACTIVATE()
END_MESSAGE_MAP()
// 绘制窗口的标题条,参数 bActive 代表窗口的当前激活状态
void CMyWnd::PaintTitleBar(BOOL bActive)
{
// 创建代表整个窗口的显示设备上下文对象
CWindowDC dc(this);
CRect rc;
// 获得窗口矩形及其宽度
GetWindowRect(rc);
UINT nWidth=rc。Width();
// 获得窗口边框的度量
UINT nXFrame=GetSystemMetrics(SM_CXSIZEFRAME);
UINT nYFrame=GetSystemMetrics(SM_CYSIZEFRAME);
// 获得窗口标题条的高度
UINT nYCaption=GetSystemMetrics(SM_CYCAPTION);
COLORREF cr;
if (bActive)
{
// 获得当窗口处于激活状态时其标题条的颜色
…………………………………………………………Page 522……………………………………………………………
cr=GetSysColor(COLOR_ACTIVECAPTION);
// 按从红到绿,再到蓝的渐变规律绘制标题条
for (UINT j=nYFrame; j
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!