登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 入门基础 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

游戏编程起源(初学者)Ⅴ
发表日期:2007-01-17作者:[转贴] 出处:  

★第三章 跟踪你的窗口和使用GDI

☆ 简介
如果你看过了头两章,你或许已经在问我什么时候能给你讲一点有成就感的东东呢?OK,时候到了。这次我们将学习WINDOWS GDI(图形设备接口)和其它一些相关的东西,象响应用户输入和处理Windows产生的一些消息。至于显示图形,我们将接触三个课题:文本显示,绘制象素,显示位图。我们先来研究一下几个Windows消息的细节。
重复的话:你需要C语言的基础知识,最好看过上两章。由于本章将使你能做一个具体的图形DEMO,有一个源代码例程附在本章后面。是用Visual C++写的和编译的,所以吗,最好同我保持一致哦!好了,开动吧!

☆ 设备上下文
在第一章里,我们创建和注册了一个窗口类,其中有一行定义了窗口的风格(功能),是这个样子:

sampleClass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; // standard settings


其中三个属性是很一般的,但这个——CS_OWNDC,需要解释一下。如果你记得,我曾经告诉过你这个属性允许窗口有自己独特的设备上下文,但直到现在,我们还没有具体的讲,OK,时间到了,开讲!
设备上下文是一个结构,是一个表现一组图形对象和属性的结构,还有一些输出设备的设置和属性。使用设备上下文允许你直接操纵图形,不用考虑低级细节。Windows GDI是一个图形翻译系统,是介于应用程序和图形硬件之间的一层。GDI可以输出到任意的兼容设备,不过最常使用的设备是视频监视器、图形硬拷贝设备(如打印机或绘图仪),或者是内存中的图元文本。GDI函数能够绘制直线、曲线、封闭的图形和文本。所有访问GDI的Windows函数都需要一个设备上下文句柄作为参数。感谢上帝,这是非常容易做到的。你若想得到一个窗口的设备上下文句柄,你可以用这个函数:

HDC GetDC(
    HWND hWnd  // handle to a window
);


很简单,是不是?所有你做的是,把要操作的窗口的句柄传递给它,然后返回一个设备上下文句柄。如果你传递的是NULL,将返回整个屏幕的设备上下文(DC,以后都用DC表示)句柄。如果函数调用失败,将返回NULL。
设备上下文不仅仅处理图形,但我们习惯于泛泛的认为它是处理图形的。处理显示图形的DC类型,称作显示DC,处理打印的,称作打印DC;处理位图数据的,称作内存DC,还有其它一些设备DC。感觉有点复杂吧,不要紧,这是Windows,它的主要功能就是迷惑群众。^_^一旦我们接触一些代码,就不会觉得难了。
当你结束使用DC时,一定要释放它,也就是释放它占用的内存空间。要把这种思想贯穿到以后的编程中去,占用了内存,不用时要释放,切记!释放DC是一个很简单的函数:

int ReleaseDC(
    HWND hWnd, // handle to window
    HDC hDC    // handle to device context
);


若成功释放,返回值是1,否则是0。参数有注释,我还是说一下:
HWND hWnd:你所要控制的那个窗口的句柄。如果你开始传递的是NULL,现在还要传递NULL。
HDC hDC:DC的句柄。
在用DC和GDI进行图形显示前,我们先看看创建窗口实例时要遇到的几条重要的消息。我将要提到的四条消息是:WM_MOVE、WM_SIZE、WM_ACTIVATE、WM_PAINT。

☆ 追踪窗口状态
头两个是很简单的。当窗口被用户移动时将发送WM_MOVE消息,窗口新位置的坐标储存在lparam中。(还记得吗,消息在lparam和wparam中被进一步描述,它们是消息控制函数的参数)lparam的低端字中存储窗口客户区左上角的坐标x,高端字中存储坐标y。
当窗口的大小被改变时,将发送WM_SIZE消息。同WM_MOVE消息差不多,lparam的低端字中存储客户区的宽度,高端字存储高度。同WM_MOVE不同的是,wparam参数也控制了一些重要的东西。它可以是下列中任意一个值:
※ SIZE_MAXHIDE:其它的窗口被最大化了。
※ SIZE_MAXIMIZED:本窗口被最大化了。
※ SIZE_MAXSHOW:其它的窗口被还原了。
※ SIZE_MINIMIZED:本窗口被最小化了。
※ SIZE_RESTORED:窗口被改变了尺寸,但既没最大化,也没有最小化。
当我编写窗口实例时,我通常喜欢把窗口的当前位置和大小保留在几个全局变量里。假设我们命名这些全局变量为xPos,yPos,xSize和ySize,你最好这样控制WM_SIZE和WM_MOVE这两个消息:

if (msg == WM_SIZE)
{
    xSize = LOWORD(lparam);
    ySize = HIWORD(lparam);
}
if (msg == WM_MOVE)
{
    xPos = LOWORD(lparam);
    yPos = HIWORD(lparam);
}


现在轮到WM_ACTIVATE消息了。它告诉你一个新窗口被激活。这是很有用的,因为如果出现优先的申请,你就不可能处理程序里的所有逻辑。有时,例如写一个全屏的DIRECTX程序,忽略WM_ACTIVATE消息将导致你的程序出现致命的错误,可能它做了一些你不希望它做的事情。在任何情况下,守候WM_ACTIVATE消息从而采取行动,是一个好主意。
窗口被激活和被解除激活都会发出WM_ACTIVATE消息,我们可以通过检测wparam的低端字来得知是被激活还是被取消。这将有三种可能的值:
※ WA_CLICKACTIVE:窗口被鼠标激活。
※ WA_ACTIVE:窗口被其它东西激活。(键盘、函数调用、等等)
※ WA_INACTIVE:窗口被解除激活。
为了处理这个消息,我保留了另一个全局变量bFocus,当接收到WM_ACTIVATE消息,它的值将改变。示例如下:

if (msg == WM_ACTIVATE)
{
    if (LOWORD(wparam) == WA_INACTIVE)
        focus = FALSE;
    else
        focus = TRUE;

    // tell Windows we handled it
    return(0);
}


有两个相关联的消息WM_KILLFOCUS和WM_SETFOCUS,在窗口接收到输入焦点的时候,Windows消息WM_SETFOCUS被发送给它,在失去焦点的时候则发送WM_KILLFOCUS消息。应用程序可以截取这些消息以得知输入焦点的任何改变情况。什么是输入焦点呢?存有输入焦点的应用程序(窗口)就是被激活的那个窗口。你就认为被激活的窗口就是输入焦点就行了。因为可能出现没有窗口具有输入焦点,所以我建议用WM_ACTIVATE消息跟踪你的窗口状态。(有些胡涂?不要紧,你就记住用WM_ACTIVATE就行了)往下进行。

☆ WM_PAINT 消息
WN_PAINT消息通知程序,全部或部分客户窗口需要重新绘制。当用户在最小化、重叠或调整客户窗口区域的时候,就会产生这条消息。重新绘制,你需要做两件事,首先是要用到WM_PAINT消息专用的一对函数,第一个是BeginPaint()函数,这是它的原形:

HDC BeginPaint(
    HWND hwnd,             // handle to window
    LPPAINTSTRUCT lpPaint  // pointer to structure for paint information
);


在我告诉你返回值是什么之前,让我们先看看参数:
HWND hwnd:需要重绘的窗口的句柄。你应该已经对于这种参数比较熟悉了。
LPPAINTSTRUCT lpPaint:这是很重要的一个。是指向PAINTSTRUCT结构的指针,该结构包含所有的要被重绘区域的信息。
继续之前,我应该给你看看PAINTSTRUCT结构:

typedef struct tagPAINTSTRUCT { // ps
    HDC hdc;
    BOOL fErase;
    RECT rcPaint;
    BOOL fRestore;
    BOOL fIncUpdate;
    BYTE rgbReserved[32];
} PAINTSTRUCT;


结构内的成员如下:
HDC hdc:哈哈,有理由复习一下设备上下文(DC,有的书中叫“设备描述表”)了。这是要被刷新区域的句柄。
BOOL fErase:指明应用程序是否应该抹去背景。如果是FALSE,说明系统已经删除了背景。还记得在Windows类中我们曾经用黑色画刷定义了一个背景吗?这就意味着系统将用这个画刷抹去无效的区域。
RECT rcPaint:这是最重要的一个成员。它将告诉你需要被重绘的无效区域的矩形。我将稍后告诉你RECT结构。
BOOL fRestore,BOOL fIncUpdate,BYTE rgbReserved[32]:好消息,这些是保留成员,为老Windows服务的,所有你我都不必管它们。:)
现在我已经给你看了这么多,这就是BeginPaint()函数的全部。它做了三件事儿。首先,它使窗口再次有效,直到下一次被改变,WM_PAINT消息发出前,这个窗口都是有效的。第二,如果在窗口类(Windows class)里定义了背景画刷,就像我们做过的那样,就用这个画刷重绘无效的区域。(所谓无效,就是被改变的)第三,返回了被重绘区域的DC句柄。重绘的区域,是由RECT结构定义的:

typedef struct _RECT {
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
} RECT;


我们已经指出这个结构描绘了一个矩形,但是有一件事情需要说说。RECT包含左上角,但不包含右下角。什么意思呢?让我们先定义一个RECT对象:

RECT myRect = {0, 0, 5, 5};

这个RECT包含象素(0,0),但是没有达到(5,5),所以矩形的右下角实际是(4,4)。看起来没有什么意义,但是你得习惯它。
现在,还记得我所说的关于使用DC的事儿吗?一旦你用完了,你就必须释放它。OK,你记起来了,用EndPaint()函数释放。回应WM_PAINT消息,每次调用完BeginPaint()函数,必须匹配一个EndPaint()函数释放DC。这是函数的原形:

BOOL EndPaint(
    HWND hWnd,                 // handle to window
    CONST PAINTSTRUCT *lpPaint // pointer to structure for paint data
);


函数通过返回TRUE或FALSE分别表明成功还是失败。有两个简单的参数:
HWND hWnd:就是窗口的句柄。
CONST PAINSTRUCT *lpPaint:指向PAINTSTRUCT类型的结构变量地址。同BeginPaint()的第二个参数是一回事。不要被CONST迷惑了,它只是保证和确认函数没有改变结构的内容。
你还可以通过调用ValidateRect()函数代替BeginPaint()函数使得窗口再次有效。但你得手工操作一切。可能我们真的什么时候就要用到它。所以给你它的原形:

BOOL ValidateRect(
    HWND hWnd,         // handle of window
    CONST RECT *lpRect // address of validation rectangle coordinates
);

通过返回TRUE或FALSE来确定函数调用成功还是失败。参数很简单:
HWND hWnd:烦不烦,我不说了:)
CONST RECT *lpRect:是指向RECT结构是否有效的指针。如果你传递NULL,则整个客户区域都是有效的。
现在把以上讲到的做个样子给你看吧,假设我们已经定义了一个全局的变量hMainWindow作为我们的窗口句柄。

if (msg == WM_PAINT)
{
    PAINTSTRUCT ps; // declare a PAINTSTRUCT for use with this message
    HDC hdc; // display device context for graphics calls

    hdc = BeginPaint(hMainWindow, &ps); // validate the window

    // your painting goes here!

    EndPaint(hMainWindow, &ps); // release the DC

    // tell Windows we took care of it
    return(0);
}


这段代码很简单,也没做什么令人兴奋的事儿!OK,如果你不想用窗口类里的默认画刷重绘窗口,你必须自己做一些事情,包括使用我们还没有讲的图形部分。永远不要害怕,我们过一会儿就讲。现在我们在讨论消息,还有一些事情我必须解释。

☆ 关闭你的应用程序(关闭窗口)
待续。。。。。。

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 游戏编程起源(初学者)Ⅴ

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.0031