Windows程序设计

Windows程序设计

窗口与消息

windows向应用程序发送了一条消息,其实现是windows调用了该程序内部的一个函数——这个函数是你写的,而且是该程序的核心,此函数的参数描述了由windows所发送了并由你的程序所接收的特定消息,这个函数被称为“窗口过程”。

WINCLASS结构体

在调用窗口前需要对WINCLASS结构体进行初始化,设置窗口的属性,然后再调用RegisterClass函数进行窗口类的注册。

typedef struct tagWNDCLASSW {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;

style为设定的类风格,使用按位或运算,
lpfnWndProc为设置窗口过程。
cbClsExtra和cbWndExtra 用于在类结构和Windows内部维护的窗口结构中预留一些额外的空间。
hInstance为设置应用程序的实例句柄,为WinMain中的第一个参数
hIcon为设置所有基于该窗口类的窗口设定一个图标,当获取预定义的图标句柄是,需要调用函数LoadIcon,并将第一个参数设为NULL,而当加载自定义图标时,一个参数为hInstance(程序的实例句柄),第二个参数用于标识该图标。
hCursor为设置鼠标指针的句柄,使用的是LoadCursor函数。与LoadIcon类似。
hbrBackGround为设置窗口的客户区的背景色
lpszMenuName为设置窗口类的菜单
lpszClassName为设置窗口类的名字。

窗口创建

由于窗口类只是定义了窗口的一般的特征,英雌基于同一个窗口类可以创建许多不同的窗口,在调用CreateWindow函数来创建窗口时,可以指定许多与窗口有关的细节信息。

hwnd = CreateWindow(szAppName,                      //窗口类名称                     
                        TEXT("The Hello Program"),  //窗口标题
                        WS_OVERLAPPED,              //窗口风格,或称为窗口格式
                        CW_USEDEFAULT,              //初始x坐标
                        CW_USEDEFAULT,              //初始y坐标
                        CW_USEDEFAULT,              //初始x方向尺寸
                        CW_USEDEFAULT,              //初始y方向尺寸
                        NULL,                       //父窗口句柄
                        NULL,                       //窗口菜单句柄
                        hInstance,                  //程序实例句柄
                        NULL);                      //创建参数

窗口的显示

当CreateWindow调用返回时,窗口已在Windows内部被创建。但是要将窗口显示在屏幕上,还需要调用另外两个函数,第一个函数为:ShowWindow(hwnd, iCmdShow); 第一个参数是指向刚才由CreateWindow所创建的窗口的句柄,第二个参数是WinMain函数所接收的iCmdShow值。该参数决定着窗口在屏幕中的初始显示形式。
第二个函数为UpdateWindow使得客户区重绘。

消息循环

在UpdateWindow被调用之后,新建窗口在屏幕中便完全可见了,此时,该程序必须能够接收来自用户的键盘输入和鼠标输入,Windows为当前在其中运行的每一个Windows程序都维护了一个消息队列。当输入事件发生后,Windows会自动将这些事件转换为消息,并将其放置在应用程序的消息队列中。
程序中执行一段名为“消息循环”的代码段来从该消息队列中获取消息

while(GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

其中msg是一个结构变量

typedef struct tagMSG {
HWND        hwnd;
UINT        message;
WPARAM      wParam;
LPARAM      lParam;
DWORD       time;
POINT       pt;
#ifdef _MAC
DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

其中hwnd 为消息所指向的窗口的句柄。
message 消息标识符,这是一个用于标识消息的数字。
wParam 一个32位的消息参数,该参数的含义和取值取决于具体的消息
lParam 另外一个32位的消息参数,该参数的含义和取值同样取决于具体消息
time 消息进入消息队列的时间
pt 消息进入消息队列中的时鼠标指针的位置坐标。
TranslateMessage(&msg);为将msg结构返还给Windows以进行某些键盘消息的转换。
DispatchMessage(&msg);为将msg结构再次返回给Windows。

窗口过程

窗口过程的名称可以任意命名,一个Windows程序可包含多个窗口过程,但一个窗口过程总是与一个通过调用RegisterClass注册的特定窗口类相关联。CreateWindow函数基于特定的窗口类创建窗口,而基于同一个窗口类则可创建多个窗口。
窗口过程总是按照如下方式来定义:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

窗口过程的4个参数与MSG结构的前4个字段是一一对应的。第一个参数是hwnd,表示接收消息的窗口的句柄,它与CreateWindow函数返回的句柄相同。
第二个参数与MSG结构的message字段对应,是一个标识消息的数字。最后两个参数是32位的消息参数,用于提供关于该消息的更丰富的信息。
应用程序通常并不直接对窗口过程进行调用,窗口过程几乎总是由Windows自身调用的。应用程序如果希望调用自身的窗口过程,则可通过调用函数SendMessage来实现。

消息的处理

窗口过程所接收的每条消息都由一个数字来标识,即窗口过程的message参数。在对与所有窗口没有处理的消息进行默认处理可以使用DefWindowProc函数。这个过程是非常重要的。

绘制和重绘

Windows是一个消息驱动的系统。他使用两种方式把各种事件通知给应用程序:把消息放在应用程序的消息队列中,或者向适当的窗口程序直接发送到消息。
WM_PAINT 消息发生的事件如下:

  • 用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来
  • 用户调整窗口的大小。
  • 程序调用ScrollWindow或ScrollDC函数滚动客户区
  • 程序调用InvalidateRect或InvalidateRgn函数显示生成WM_PAINT消息

有效矩形和无效矩形
尽管窗口过程必须能够在收到WM_PAINT消息时更新整个客户区,但通常它只需要更新其中的一部分,最常见的是更新其中的一个矩形区域。需要重新绘制的部分被称为“无效区域”或“更新区域”

GDI

绘制一个窗口的客户区需要调用Windows的图像设备接口(GDI)函数。在GDI函数中,几乎所有的GDI函数都需要设备环境句柄作为函数的第一个参数。

设备环境

设备环境句柄是程序窗口使用GDI函数的“通行证”。有了设备环境句柄,就可以随心所欲地绘制你的客户区。
设备环境实际上是GDI内部维护的一个数据结构。设备环境与特定的显示设备想关联。对于视频显示,设备环境通常与屏幕上的一个特定的窗口相关联。
设备环境红的某些值是图形“属性”。这些属性决定了GDI绘图函数的工作细节。例如文本的颜色、文本背景的颜色、函数参数x和y如何映射到窗口的客户区,以及windows用什么显示字体显示文本。
程序在绘制前必须获取一个设备环境句柄,在获取环境句柄后,Windows会在内部设备环境结构中填入默认的属性值。
当程序完成了对客户区的绘制后,它必须释放设备环境句柄。在程序释放句柄之后,这个句柄不再有效并且不能再被使用。

获取设备环境句柄

在处理WM_PAINT消息时可以使用以下两个函数获取设备环境句柄:BeginPaint和EndPaint。两个函数都需要两个参数:一是窗口的句柄,这是窗口消息处理过程的参数;另一个是一个类型为PAINTSTRUCT结构的变量的地址(通常被命名为ps)。
在处理WM_PAINT消息时,窗口过程首先调用BeginPaint函数,该函数擦除无效区域的背景以便绘图。同时还会填充ps结构的各个字段。函数的返回值就是设备环境句柄(HDC hdc)

case WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);
    ....//使用GDI函数
    EndPaint(hwndm &ps);
    return 0;

PAINTSTRUCT结构

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

其中hdc为设备环境句柄,为BeginPaint函数的返回值
fErase字段一般被设置为FALSE。这意味着WIndows在先前的BeginPaint函数中已经擦除了无效区域的背景。
尽管最好让程序在处理WM_PAINT消息时才更新整个客户去,但有时也会发现在处理非WM_PAINT消息时绘制部分客户区也是很有用的。有些时候,还需要设备环境句柄用作其他用途,例如获取设备环境信息。
可以调用GetDC函数来获得窗口客户区的设备环境句柄,在使用完以后,调用ReleaseDC函数将它释放

hdc = GetDC(hwnd);
....
ReleaseDC(hwnd, hdc);

此两个函数必须成对使用,在处理一条消息时,当调用GetDC函数后,应该在退出窗口过程之前调用ReleaseDC。
与BeginPaint函数返回的设备环境句柄不同,从GetDC返回的设备环境句柄中裁剪矩形是整个客户去。这意味着你可以在客户区的任意部分绘制,而不仅仅是在无效矩形里,也就是说如果不存在无效矩形也没有关系。GetDC不会将无效区域有效化,如果需要将整个客户区有效化,可以调用下面的函数:

ValidateRect(hwnd, NULL);

GetDC和ReleaseDC函数用于处理键盘消息或鼠标消息。
另一个与GetDC类似的函数是GetWindowDC。GetDC返回的是窗口客户区的设备环境句柄,GetWindowDC返回的则是整个窗口的设备环境句柄。

TEXTOUT函数详解

TEXTOUT是显示文本的最重要的GDI函数。

TextOut(hdc, x, y, psText, iLength);

第一个参数为设备环境句柄:它既可以从GetDC返回的hdc值,也可以是处理WM_PAINT消息时从BeginPaint返回的hdc值。
参数psText是只想字符串的指针,而iLength是字符串中的字符数。如果psText指向一个Unicode字符串,则字符串占用的字节数将是iLength的两倍。
参数x和y决定着输出字符串在客户区的起始位置。x是水平位置,而y是垂直位置。

不同的显示器有着不同的分配率,程序可以调用GetSystemMetrics函数来获取用户界面的尺寸,同样的,通过调用GetTextMetrics函数,程序可以获取字体尺寸。GetTextMetrics函数需要一个设备环境句柄。

客户区的尺寸

在Windows应用程序中,窗口的尺寸可以有很大的变化。我们可以用CetClientRect函数来获取客户区的大小。但是这种方法效率比较低,更好的办法是在窗口过程处理WM_SIZE消息时获取窗口的客户区大小。当窗口的大小发生变化时,Windows会向窗口过程发送一条WM_SIZE消息。相应的lParam变量的低位字是客户区的宽度,而高位字是高度。可以在窗口过程中定义两个静态变量来保存着两个值

case WM_SIZE:
    cxClient = LOWORD(lParam);
    cyClient = HIWORD(lParam);
    return 0;

其中LOWORD和HIWORD是两个宏定义函数。分别取低位字和高位字。

滚动条

滚动条是图形用户界面中最好的特性之一。它们很容易使用,并且提供了很好的视觉效果。滚动条既可以垂直放置,也可以水平放置。
在应用程序的窗口中包括滚动条相当容易。只需在CreateWindow的第三个参数中包括窗口风格标识符WS_VSCROLL(垂直)或WS_HSCROLL(水平)。垂直滚动条的宽度和水平滚动条的高度都是固定的,如果需要,可以通过调用GetSystemMetrics函数来获取它们的值。
Windows负责处理滚动条中的所有鼠标消息,但是,滚动条并没有自动对应的键盘接口。如果想将方向键对应到滚动条上,则必须显式地提供相应的对应关系。

滚动条的范围和位置

每个滚动条都有相应的“范围”和“位置”。滚动条的范围是一对整数。位置是指滑块在范围中所处的位置。
在默认状态下,滚动条的范围是0~100.不过可以调用函数SetScrollRange()来设置范围。

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

里面的iBar参数要么是SB_VERT或者SB_HORZ,如果需要Windows根据新的范围来重绘滚动条时,请将bRedraw参数设为TRUE。
滑块的位置总是一个离散的整数值。
在程序中使用滚动条时,程序需要和Windows共同负责维护滚动条以及滑块在滚动条中的位置
Windows负责如下任务:

  • 处理滚动条中的所有鼠标消息
  • 当用户单机滚动条时,提供一种反向显示的闪烁
  • 当用户拖动滑块时,在滚动条内移动滑块。
  • 想拥有滚动条的窗口的窗口过程发送滚动条消息

程序负责如下任务:

  • 初始化滚动条的范围和位置
  • 处理传送给窗口过程的滚动条消息
  • 更新滑块的位置
  • 根据滚动条的变化更行客户区的内容

滚动条消息

当用户单击滚动条或拖动滑块时,Windows向窗口过程发送WM_VSCROLL消息或WM_HSCROLL消息。在滚动条上的任何鼠标动作会产生至少两条消息:一条在鼠标按键下,另一条在鼠标松开时。
像所有的消息一样,上两条消息都伴随着wParam和lParam消息参数,当滚动条时窗口的一部分时,可以囫囵lParam参数:它只用于滚动条时子窗口时,通常在对话框中。
wParam参数被分为低位字和高位字。wParam的低位字代表了鼠标在滚动条上的动作。这个值被称为“通知码”。
如果在滚动条的不同部分按住鼠标键不放,程序可能收到多条滚动条消息。当松开鼠标键时,程序会收到一条带有SB_ENDSCROLL通知码的消息。
将鼠标放在滑块上然后按下鼠标键时,可以移动滑块。这将会生成带SB_THUMBTRACK和SB_THUMBPOSITION通知码的滚动消息。当wParam的低位字是SB_THUMBTRACK时,wParam的高位字是用户拖动的当前位置,这个位置处于滚动条范围的最小值和最大值之间。当wParam的低位字是SB_THUMBPOSITION时,wParam的高位字是用户松开鼠标键时滑块的最终位置。对于其他的滚动条动作,wParam的高位字应被忽略。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值