Menu
Woocommerce Menu

如果客户区的某个区域需要重画了,它作为用户与应用程序间的主界面来提供服务

0 Comment


第四章 Windows图形界面,第四章图形界面

学习《Windows程序设计》记录

 

概念贴士:

1.  每个GUI应用程序至少应该创建一个窗口,称为主窗口,它作为用户与应用程序间的主界面来提供服务。大多数应用程序也直接或间接地创建其他窗口,来完成与主窗口相关的工作。

 

2.  应用程序的主窗口包括标题栏、菜单栏、Windows系统菜单、最小化按钮、最大化按钮、回复按钮、关闭按钮、可改变大小的边框、窗口客户区、垂直滚动条和水平滚动条。

 

3.  VC++6.0创建GUI程序:  1)创建VC++6.0,选择命令“文件”,点击“新建”;

                2)选择“工程”,点击“Win32
Application”选项;

                3)输入工程名、存放路径;

                4)点击OK按钮,选择第二项“一个简单Win32应用程序”;

                5)点击“完成”按钮,完成GUI程序工程创建。

 

4.  Win32程序的入口函数将是WinMain函数,而不是控制台程序的main函数。

 

5.  GUI应用程序的入口函数是WinMain,这是一个自定义的回调函数。其中APIENTRY是_stdcall的宏定义,说明WinMain函数采用的是Windows标准调用方式。

 

6.  用户创建窗口后,就要对窗口的行为负责。当Windows向程序发送消息时,它调用程序中的一个函数,这个函数的参数精确地描述了Windows发送的消息。在程序中称这个函数为窗口函数(Window
Procedure)或消息处理函数。它是一个自定义的回调函数。

 

7.  系统为应用程序传递所有的输入到它的各个窗口,每个窗口都关联一个窗口函数,每当这个窗口有输入时,系统调用该函数。窗口函数处理输入,然后再将控制权交给系统。

 

8.  基于窗口界面的Windows应用程序是事件驱动(event-driven)的。为了取得输入,它们并不做显示的函数调用,而是等待系统传递输入给它们。

 

9.  在桌面上显示一个窗口的具体步骤(也就是主程序的结构流程):

        1)注册窗口类(RegisterClassEx);

        2)创建窗口(CreateWindowEx);

        3)在桌面显示窗口(ShowWindow);

        4)更新窗口客户区(UpdateWindow);

        5)进入无限的消息获取和处理的循环。  首先是获取消息(GetMessage).如果有消息到达,则将消息分派到回到函数进行处理(DispatchMessage)。如果消息是WM_QUIT,则GetMessage函数返回FALSE,整个消息循环结束。消息具体的处理过程是在MainWndProc函数中进行的。

 

 

代码解释:

FirstWindow

  PS:这是一个最简单的窗口程序源代码,作用是弹出一个典型的Windows窗口。这些代码可作为今后用API写Windows程序的基本框架。

 1 // 窗口学习01.cpp : Defines the entry point for the application.
 2 //
 3 
 4 #include "stdafx.h"
 5 LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
 6 int APIENTRY WinMain(HINSTANCE hInstance,
 7                      HINSTANCE hPrevInstance,
 8                      LPSTR     lpCmdLine,
 9                      int       nCmdShow)
10 {
11      // TODO: Place code here.
12     char szClassName[]="MainWClass";
13     WNDCLASSEX wndclass;
14     //用于描述主窗口的参数填充WNDCLASSEX结构
15     wndclass.cbSize=sizeof(wndclass);                    //结构的大小
16     wndclass.style=CS_HREDRAW|CS_VREDRAW;                //指定如果大小改变就重画
17     wndclass.lpfnWndProc=MainWndProc;                    //窗口函数指针
18     wndclass.cbClsExtra=0;                                //没有额外的类内存
19     wndclass.cbWndExtra=0;                                //没有额外的窗口内存;
20     wndclass.hInstance=hInstance;                        //实例句柄
21     wndclass.hIcon=::LoadIcon(NULL,IDI_APPLICATION);    //使用预定义图标
22     wndclass.hCursor=::LoadCursor(NULL,IDC_ARROW);        //使用预定义的光标
23     wndclass.hbrBackground=(HBRUSH)::GetStockObject(WHITE_BRUSH);    //使用白色背景画刷
24     wndclass.lpszMenuName=NULL;                            //不指定菜单
25     wndclass.lpszClassName=szClassName;                    //窗口类的名称
26     wndclass.hIconSm=NULL;                                //没有类的小图标
27     
28     //注册这个窗口类
29     ::RegisterClassEx(&wndclass);
30     
31     //创建主窗口
32     HWND hwnd=::CreateWindowEx(
33         0,                                              //dwExStyle,扩展样式
34         szClassName,                                    //lpClassName,类名
35         "My first Window!",                             //lpWindowName,标题
36         WS_OVERLAPPEDWINDOW,                            //dwStyle,窗口风格
37         CW_USEDEFAULT,                                  //X,初始X坐标
38         CW_USEDEFAULT,                                  //Y,初始Y坐标
39         CW_USEDEFAULT,                                  //nWidth,宽度
40         CW_USEDEFAULT,                                  //nHeight,高度
41         NULL,                                           //hWndParent,父窗口句柄
42         NULL,                                           //hMenu,菜单句柄
43         hInstance,                                      //hInstance,程序实例句柄
44         NULL);                                          //lpParam,用户数据
45         
46     if(hwnd==NULL)
47     {
48         ::MessageBox(NULL,"创建窗口出错!","error",MB_OK);
49         return -1;
50     }
51 
52     //显示窗口,刷新窗口客户区
53     ::ShowWindow(hwnd,nCmdShow);
54     ::UpdateWindow(hwnd);
55 
56     //从消息队列中取出消息,交给窗口函数处理,知道GetMessage返回FALSE,结束消息循环
57     MSG msg;
58     while(::GetMessage(&msg,NULL,0,0))
59     {
60         //转化键盘消息
61         ::TranslateMessage(&msg);
62         //将消息发送到相应的窗口函数
63         ::DispatchMessage(&msg);
64     }
65 
66     //当GetMessage返回FALSE时程序结束
67     return msg.wParam;
68 }
69 
70 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
71 {
72     char szText[]="最简单的窗口程序!";
73     switch(message)
74     {
75     case WM_PAINT:                //窗口客户区需要重画
76         {
77             HDC hdc;
78             PAINTSTRUCT ps;
79 
80             //使无效的客户区变得有效,并取得设备环境句柄
81             hdc=::BeginPaint(hwnd,&ps);
82             //显示文字
83             ::TextOut(hdc,10,10,szText,strlen(szText));
84             ::EndPaint(hwnd,&ps);
85             return 0;
86         }
87     case WM_DESTROY:            //正在销毁窗口
88 
89         //向消息队列投递一个WM_QUIT消息,促使GetMessage函数返回0,结束消息循环
90         ::PostQuitMessage(0);
91         return 0;
92     }
93 
94     //将我们不处理的消息交给系统做默认处理
95     return ::DefWindowProc(hwnd,message,wParam,lParam);
96 }

 

 

 程序分析:

1.  注册窗口类:

  注册窗口类的API函数是RegisterClassEx,最后的“Ex”是扩展的意思,因为它是Win16的RegisterClass函数的拓展。一个窗口类定义了窗口的一些主要属性,如:图标、光标、背景色和负责处理消息的窗口函数等。这些属性定义在WNDCLASSEX结构中。

 1 typedef struct_WNDCLASSEX{
 2     UINT cbSize;                        //WNDCLASSEX结构的大小
 3     UINT style;                         //从这个窗口类派生的窗口具有的风格
 4     WNDPROC lpfnWndProc;                //即 window procedure,窗口消息处理函数指针
 5     int cbClsExtra;                     //指定紧跟在窗口类结构后的附加字节数
 6     int cbWndExtra;                     //指定紧跟在窗口事例后的附加字节数
 7     HANDLE hInstance;                   //本模板的实例句柄
 8     HICON hIcon;                        //窗口左上角图标的句柄
 9     HCURSOR hCursor;                    //光标的句柄
10     HBRUSH hbrBackground;               //背景画刷的句柄
11     LPCTSTR lpszMenuName;               //菜单名
12     LPCTSTR lpszClassName;              //该窗口类的名称
13     HICON hIconSm;                      //小图标句柄
14 }WNDCLASSEX;

  PS:

  RegisterClassEx的唯一参数是这个结构的地址。注册窗口类后就可以将类名和其窗口函数、类的风格及其他的类属性联系起来。当进程在CreateWindowEx函数中指定一个类名的时候,系统就用这个窗口函数、风格和与此类名相关的其他属性创建窗口。

  主程序中CS_HREDRAW|CS_VREDRAW风格指定如果窗口客户区的宽度或高度改变了,则重画这个窗口。前缀CS_意为class
style,在WINUSER.H中定义了全部可选样式。

  主程序中LoadIcon函数装载了一个预定义的图标(命名为IDI_APPLICATION),LoadCursor函数装载了一个预定义的光标(命名为IDC_ARROW)。如果要装载自定义的图标或光标的话,应该先向工程中添加一个资源脚本(后面打字程序将会提到),然后再通过菜单命令“Insert/Resource…”添加这些资源。

  WHITE_BRUSH是一个Windows预定义的画刷对象类型,GetStockObject函数取得这个画刷对象的句柄,传递给hbrBackground成员。我们也可以自己创建一个画刷对象,以便指定喜欢的颜色作为窗口的背景色。例如下面代码将窗口的背景色设为天蓝色。

wndclass.hbrBackground=::CreateSolidBrush(RGB(0xa6,0xca,0xf0));            //创建一个纯色的刷子
......
::DeleteObject(wndclass.hbrBackground);                                    //最后别忘了删除创建的刷子,释放资源

  填充完WNDCLASSEX结构,就可以进行注册了。RegisterClassEx函数调用失败将返回0.

 

2.  创建窗口:

  要创建窗口,用注册的窗口类的类名调用CreateWindowEx函数即可。

 1 HWND hwnd=::CreateWindowEx(
 2                 0,                                        //dwExStyle,拓展样式
 3                 szClassName,                              //lpClassName,类名
 4                 "My first Window!",                       //lpWindowName,标题
 5                 WS_OVERLAPPEDWINDOW,                      //dwStyle,窗口风格
 6                 CW_USEDEFAULT,                            //X,初始X坐标
 7                 CW_USEDEFAULT,                            //Y,初始Y坐标
 8                 CW_USEDEFAULT,                            //nWidth,宽度
 9                 CW_USEDEFAULT,                            //nHeight,高度
10                 NULL,                                     //hWndParent,父窗口句柄
11                 NULL,                                     //hMenu,菜单句柄
12                 hInstance,                                //hInstance,程序实例句柄
13                 NULL);                                    //lpParam,用户数据
14        

  PS:

  函数调用成功将返回窗口句柄,失败返回NULL。第四个参数dwStyle的值是WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped
Window)。由它指定的窗口有标题栏、系统菜单、可以改变大小的边框,以及最大化、最小化和关闭按钮。这个一个标准窗口的样式。

  下面列出一些常见风格的定义,它们是以WS(Windows
Style的缩写)为前缀的预定义的值。

    • WS_BORDER  创建一个单边框的窗口
    • WS_CAPTION    创建一个有标题框的窗口(包括WS_BODER风格)
    • WS_CHIlD  创建一个子窗口。这个风格不能与WS_POPVP风格合用
    • WS_DISABLED  创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息
    • WS_DLGFRAME  创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条
    • WS_HSCROLL  创建一个有水平滚动条的窗口
    • WS_VSCROLL  创建一个有垂直滚动条的窗口
    • WS_ICONIC  创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同
    • WS_MAXIMIZE  创建一个具有最大化按钮的窗口。该风格不能喝WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。
    • WS_THICKFRAME  创建一个可调边框的窗口,与WS_SIZEBOX风格相同
    • WS_VISIBLE  创建一个初始状态为可见的窗口

     等等。

 

3.  在桌面显示窗口:

1 ::ShowWindow(hwnd,nCmdShow);

  PS:

  ShowWindow函数用于设置指定窗口的显示状态,上面代码中的nCmdShow是系统传递给WinMain函数的参数。函数的第二个参数可以有多个不同的取值(具体情况请索引查看SDK文档),例如下面的代码将隐藏句柄hWnd指定的窗口。

::ShowWindow(hWnd,SW_HIDE);            //nCmdShow参数的取值可以是SW_SHOW、SW_HIDE、SW_MINIMIZE等

 

 4.  更新窗口客户区:

1 ::UpdateWindow(hwnd);

  PS:

  如果指定窗口的更新区域不为空的话,UpdateWindow函数通过向这个窗口发送一个WM_PAINT消息更新它的客户区。当窗口显示在屏幕上时,窗口的客户区被在WNDCLASSEX中指定的刷子擦去了,调用UpdateWindow函数将促使客户区重画,以显示其内容。

 

5.  进入无限的消息循环:

  程序下面将进入无限的循环中。在调用UpdateWindow函数之后,整个窗口已经显示在桌面上,程序必须准备从用户接受键盘和鼠标输入了。Windows为每个线程维护了一个消息队列,每当有一个输入发生,Windows就把用户的输入翻译成消息放在消息队列中。利用GetMessage函数可以从调用线程的消息队列中取出一个消息来填充MSG结构。

1 ::GetMessage(&msg,NULL,0,0);

  PS:

  如果消息队列中没有消息(即没有用户输入),这个函数会一直等待下去,知道有消息进入到消息队列为止。msg是一个MSG结构类型的变量,这个结构定义了消息的所有属性。

typedef struct tagMSG {
    HWND hwnd;                   //消息要发送的窗口句柄
    UINT message;                //消息标识符,以WM_开头的预定义值(意为Window Message)
    WPARAM wParam;               //消息的参数之一
    LPARAM lParam;               //消息的参数之二
    DWORD time                   //消息放入消息队列的时间
    POINT pt;                    //这是一个POINT数据结构,表示消息放入消息队列时的鼠标位置
}MSG,*PMSG;

  GetMessage函数从消息队列中取得的消息如果不是WM_QUIT,则返回非零值。一个WM_QUIT消息会促使GetMessage函数返回0,从而结束消息循环。

::TranslateMessage(&msg);

  此调用把键盘输入翻译成为可传递的消息。

::DispatchMessage(&msg);

  DispatchMessage函数分发一个消息到对应窗口的窗口函数。在上面的例子中,窗口函数是MainWndProc。MainWndProc处理消息后把控制权交给Windows,此时DispatchMessage函数仍然继续工作,当它返回时,消息循环队列从调用Getmessage函数开始进入下一轮循环。

 

 *6.  处理消息:

  消息处理函数接收到的所有消息都被标识为一个数字,这就是MainWndProc的第一个参数uMsg。这些数字在WINUSER.H文件中都是以WM_为前缀定义的。

  通常Windows程序设计者用一个switch和case结构来决定消息处理函数收到了什么消息,以及如何处理这个消息。所有消息处理函数不处理的消息都必须传给一个名为DefWindowProc的函数让Windows做默认处理,从DefWindowProc函数返回的值也必须从消息处理函数返回。

 1 switch(uMsg)
 2 {
 3 case WM_PAINT:
 4     /*处理WM_PAINT消息*/
 5     return 0;
 6 
 7 case WM_DESTROY:
 8     /*处理WM_DESTROY消息*/
 9     return 0;
10 
11 }
12 return ::DefWindowProc(hwnd,message,wParam,lParam);

  PS:

  必须要把所有不处理的消息交给DefWindowProc函数处理,也要把它的返回值返回给Windows,否则Windows就失去了与应用程序通信的途径,也就不能再控制窗口的行为了,这是不合法的。

  WM_PAINT消息通知应用程序窗口客户区有一块或者全部变成无效,必须刷新。这意味着窗口客户区的内容必须被重画。客户区在以下情况会变成无效:

    1)当窗口第一次被创建时,整个客户区是无效的,因为还没有向上面画任何东西。

      第一个WM_PAINT消息被发送到窗口处理函数时,程序有机会向客户区画一些东西。

    2)当改变窗口大小的时候,客户区编程无效。

      用户在填写WNDCLASSEX结构的style成员时,将它设置为CS_HREDRAW和CS_VREDRAW,这就直接促成在改变窗口大小时Windows将整个窗口变为无效。

    3)最小化窗口,再将它恢复到以前大小时,Windows没有保存整个客户区的内容。

      在图形操作系统下,需要保存的数据太多了。同样地,Windows使这个窗口无效,窗口处理函数就会收到一个WM_PAINT消息,自己负责回复客户区内容。

    4)当围着屏幕移动窗口,直到窗口被覆盖时,Windows并没有保存被覆盖的区域。

      这个区域再次显示时,它就被标识为无效。窗口处理函数会收到一个WM_PAINT消息来重画窗口的内容。

  处理WM_PAINT消息时总是以调用BeginPaint函数开始。

hdc=::BeginPaint(hwnd,&ps);
//以一个EndPaint函数调用结束
::EndPaint(hwnd,&ps);

  这两个函数中,第一个参数是窗口句柄,第二个参数是指向PAINTSTRUCT结构的指正,这个结构包含一些可以在重画客户区时使用的信息。

  在调用BeginPaint函数的时候,如果客户区的背景还没有被擦掉的话,Windows将擦除它,擦除背景时使用的刷子由WNDCLASSEX结构的hbrBackground成员指定。对BeginPain函数的调用将使整个客户区有效,然后返回设备环境句柄。在窗口的客户区显示图形和文字时,需要使用这个设备环境句柄。EndPaint函数负责释放设备环境句柄,使它变得不在能使用。DefWindowProc函数会通过调用BeginPaint和EndPaint函数使客户区有效。

  调用BeginPaint函数后,主程序中调用了TextOut函数。

1 ::TextOut(hdc,10,10,szText,strlen(szText));

  此函数用于在hdc指定的设备(这里是
显示器)上显示文字。(10,10)为坐标位置,szText为要显示的文字,strlen(szText)语句计算出了文本占用的字节数。

  每当客户区变成无效,消息处理函数WndProc都会收到一个洗呢WM_PAINT消息。响应此消息的代码取得设备环境句柄后,再一次将szText的内容显示在指定位置。

  WM_DESTROY是窗口函数必须处理的消息。当用户关闭窗口,而且此窗口已经响应了用户的请求正在关闭时,消息处理函数就会收到一个WM_DESTROY消息。当接受到这个消息的时候,说明窗口正在销毁。MainWndProc函数调用PostQuitMessage函数来响应此消息。

1 ::PostQuitMessage(0);

  这个函数向程序的消息队列中插入一个WM_QUIT消息。GetMessage函数如果从消息队列中取得的消息是WM_QUIT,它将返回0,从而促使WinMain函数离开消息循环,然后应用程序执行以下代码。

1 //当GetMessage返回0时程序结束
2 return msg.wParam;

  此时,msg.wParam的值是传给PostQuitMessage函数的参数的值。return语句将使WinMain函数返回,程序运行结束。

Windows图形界面,第四章图形界面
学习《Windows程序设计》记录 概念贴士: 1.
每个GUI应用程序至少应该创建一个窗口,称为主窗口,…

  WM_DESTROY是窗口函数必须处理的消息。当用户关闭窗口,而且此窗口已经响应了用户的请求正在关闭时,消息处理函数就会收到一个WM_DESTROY消息。当接受到这个消息的时候,说明窗口正在销毁。MainWndProc函数调用PostQuitMessage函数来响应此消息。

 1 typedef struct_WNDCLASSEX{
 2     UINT cbSize;                        //WNDCLASSEX结构的大小
 3     UINT style;                         //从这个窗口类派生的窗口具有的风格
 4     WNDPROC lpfnWndProc;                //即 window procedure,窗口消息处理函数指针
 5     int cbClsExtra;                     //指定紧跟在窗口类结构后的附加字节数
 6     int cbWndExtra;                     //指定紧跟在窗口事例后的附加字节数
 7     HANDLE hInstance;                   //本模板的实例句柄
 8     HICON hIcon;                        //窗口左上角图标的句柄
 9     HCURSOR hCursor;                    //光标的句柄
10     HBRUSH hbrBackground;               //背景画刷的句柄
11     LPCTSTR lpszMenuName;               //菜单名
12     LPCTSTR lpszClassName;              //该窗口类的名称
13     HICON hIconSm;                      //小图标句柄
14 }WNDCLASSEX;

1.使用VC++6.0编译C语言文件(.c)

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("Hello World!");
    getch();
    return 0;
}

 图片 1

图片 2

图片 3

图片 4

 

      当程序员将wcex结构按自己要求填写完成后就可以调用RegisterClass(或RegisterClassEx)函数将该类注册,这样以后凡是要创建该窗口,只需要以该类名(lpszClassName中指定)为参数调用CreateWindow,你看多方便呀,真是一举多得啊!如下Instance函数中的CreateWindow中的第一个参数“seekName”。

    3)最小化窗口,再将它恢复到以前大小时,Windows没有保存整个客户区的内容。

 

1. Developer
Studio,这是一个集成开发环境,我们日常工作的99%都是在它上面完成的,再加上它的标题赫然写着“Microsoft
Visual C++”,所以很多人理所当然的认为,那就是Visual
C++了。其实不然,虽然Developer
Studio提供了一个很好的编辑器和很多Wizard,但实际上它没有任何编译和链接程序的功能,真正完成这些工作的幕后英雄后面会介绍。我们也知道,Developer
Studio并不是专门用于VC的,它也同样用于VB,VJ,VID等Visual
Studio家族的其他同胞兄弟。所以不要把Developer Studio当成Visual C++,
它充其量只是Visual C++的一个壳子而已。这一点请切记!

[cpp] view
plain copy

 

8.  基于窗口界面的Windows应用程序是事件驱动(event-driven)的。为了取得输入,它们并不做显示的函数调用,而是等待系统传递输入给它们。

3. Platform SDK。这才是Visual C++和整个Visual
Studio的精华和灵魂,虽然我们很少能直接接触到它。大致说来,Platform
SDK是以Microsoft C/C++编译器为核心(不是Visual
C++,看清楚了),配合MASM,辅以其他一些工具和文档资料。上面说到Developer
Studio没有编译程序的功能,那么这项工作是由谁来完成的呢?是CL,是NMAKE,和其他许许多多命令行程序,这些我们看不到的程序才是构成Visual
Studio的基石。

 

 

  函数调用成功将返回窗口句柄,失败返回NULL。第四个参数dwStyle的值是WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped
Window)。由它指定的窗口有标题栏、系统菜单、可以改变大小的边框,以及最大化、最小化和关闭按钮。这个一个标准窗口的样式。

Visual C++6.0不仅是一个C++
编译器,而且是一个基于Windows操作系统的可视化集成开发环境(integrated
development environment,IDE)。Visual
C++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导Class
Wizard等开发工具。 这些组件通过一个名为Developer
Studio的组件集成为和谐的开发环境。

//MyRegisterClass函数

 

7.  系统为应用程序传递所有的输入到它的各个窗口,每个窗口都关联一个窗口函数,每当这个窗口有输入时,系统调用该函数。窗口函数处理输入,然后再将控制权交给系统。

2. MFC。从理论上来讲,MFC也不是专用于Visual C++,Borland
C++,C++Builder和Symantec C++同样可以处理MFC。同时,用Visual
C++编写代码也并不意味着一定要用MFC,只要愿意,用Visual
C++来编写SDK程序,或者使用STL,ATL,一样没有限制。不过,Visual
C++本来就是为MFC打造的,Visual
C++中的许多特征和语言扩展也是为MFC而设计的,所以用Visual
C++而不用MFC就等于抛弃了Visual C++中很大的一部分功能。但是,Visual
C++也不等于MFC。

 

 

1 ::ShowWindow(hwnd,nCmdShow);

2.使用VC++6.0创建MFC对话框程序

 图片 5

图片 6

图片 7

图片 8

图片 9

 

 

::DispatchMessage(&msg);

2.  应用程序的主窗口包括标题栏、菜单栏、Windows系统菜单、最小化按钮、最大化按钮、回复按钮、关闭按钮、可改变大小的边框、窗口客户区、垂直滚动条和水平滚动条。

3.使用API创建Win32窗口简单讲解

int APIENTRY WinMain(HINSTANCE hInstance,  //  本模块的实例句柄 

                                          HINSTANCE hPrevInstance,  //
Win16 留下的废物,现在已经不用了 

                                          LPSTR lpCmdLine,    //
 命令行参数 

                                          int nCmdShow)      //
 主窗口初始化时的显示方式 

{  //  下面这行代码是我添加的,用于弹出一个小对话框 

  ::MessageBox(NULL, “Hello, Win32 Application”, “04Win32AppDemo”,
MB_OK); 

  return 0; 

APIENTRY是__stdcall的宏定义,说明 WinMain 函数采用的是 Windows
标准调用方式。

hInstance 指定了当前模块的实例句柄。其实在 Win32 下,模块的实例句柄和模块句

柄是一样的,只是说法不同,所以可以通过以下语句获得当前可执行模块的实例句柄。 

hInstance = ( HINSTANCE )GetModuleHandle(NULL);  //
 取得应用程序的实例句柄(即模块句柄) 

GetModuleHandle
函数的惟一参数是模块的名称,函数会返回这个模块的句柄。模块句柄

的值就是该模块在内存中的首地址。如果为 GetModuleHandle 传递 NULL
的话,函数返回的

是可执行文件所在模块的模块句柄,而不管是在哪个模块中做这个调用的。 

 lpCmdLine 是命令行参数。其值由 CreateProcess
函数的第二个参数指定。通常应用程

序在初始化时检查这个参数,以决定是否打开特定文档。 

 nCmdShow 指定了窗口初始化时的显示方式。这个值也是由 CreateProcess
函数传递

的。一般以这个值为参数调用 ShowWindow
就可以了,此函数用于设置窗口的显示状态,

 

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam); 

CALLBACK 宏是__stdcall 的意思,说明采用 Windows 标准方式传递参数。hWnd
参数标

识了消息到达的窗口;uMsg  参数是一个被命名的常量(消息 ID
号),它指定了所发的消息,

当窗口函数接受到消息时,它使用消息 ID 号来决定如何处理这个消息;wParam
和 lParam 是

消息的两个参数,其值取决于 uMsg。 

 

//  窗口函数的函数原形 

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); 

int APIENTRY WinMain(HINSTANCE hInstance, 

                                          HINSTANCE hPrevInstance, 

                                          LPSTR          lpCmdLine, 

                                          int              nCmdShow) 

{  char szClassName[] = “MainWClass”;   

  WNDCLASSEX wndclass; 

  //  用描述主窗口的参数填充 WNDCLASSEX 结构 

  wndclass.cbSize = sizeof(wndclass);        //  结构的大小 

  wndclass.style = CS_HREDRAW|CS_VREDRAW;  //  指定如果大小改变就重画 

  wndclass.lpfnWndProc = MainWndProc;      //  窗口函数指针 

  wndclass.cbClsExtra = 0;          //  没有额外的类内存 

  wndclass.cbWndExtra = 0;          //  没有额外的窗口内存 

  wndclass.hInstance = hInstance;        //  实例句柄   

  wndclass.hIcon = ::LoadIcon(NULL,    IDI_APPLICATION);       //
 使用预定义图标 

  wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);        //
 使用预定义的光标 

  wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);  //
 使用白色背景画刷 

  wndclass.lpszMenuName = NULL;        //  不指定菜单 

  wndclass.lpszClassName = szClassName ;      //  窗口类的名称   

  wndclass.hIconSm = NULL;          //  没有类的小图标 

  //  注册这个窗口类 

  ::RegisterClassEx(&wndclass); 

  //  创建主窗口 

  HWND hwnd = ::CreateWindowEx(   

    0,            // dwExStyle,扩展样式   

    szClassName,        // lpClassName,类名       

    “My first Window!”,      // lpWindowName,标题     

    WS_OVERLAPPEDWINDOW,  // dwStyle,窗口风格   

    CW_USEDEFAULT,      // X,初始  X  坐标     

    CW_USEDEFAULT,      // Y,初始  Y  坐标     

    CW_USEDEFAULT,      // nWidth,宽度       

    CW_USEDEFAULT,      // nHeight,高度       

    NULL,          // hWndParent,父窗口句柄       

    NULL,          // hMenu,菜单句柄     

    hInstance,          // hlnstance,程序实例句柄     

    NULL) ;          // lpParam,用户数据       

  if(hwnd == NULL) 

  {  ::MessageBox(NULL, “创建窗口出错!”, “error”, MB_OK); 

    return -1; 

  } 

  //  显示窗口,刷新窗口客户区 

  ::ShowWindow(hwnd, nCmdShow); 

  ::UpdateWindow(hwnd); 

  //  从消息队列中取出消息,交给窗口函数处理,直到 GetMessage 返回
FALSE,结束消息循环 

  MSG msg;   

  while(::GetMessage(&msg, NULL, 0, 0)) 

  {  //  转化键盘消息 

    ::TranslateMessage(&msg); 

    //  将消息发送到相应的窗口函数 

    ::DispatchMessage(&msg); 

  } 

  //  当 GetMessage 返回 FALSE 时程序结束 

  return msg.wParam; 

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

{  char szText[] = “最简单的窗口程序!”; 

  switch (message) 

  {       

  case WM_PAINT: //  窗口客户区需要重画 

    {  HDC hdc; 

      PAINTSTRUCT ps; 

      //  使无效的客户区变的有效,并取得设备环境句柄 

      hdc = ::BeginPaint (hwnd, &ps) ;   

      //  显示文字 

      ::TextOut(hdc, 10, 10, szText, strlen(szText)); 

      ::EndPaint(hwnd, &ps); 

      return 0; 

    }   

  case WM_DESTROY: //  正在销毁窗口 

    //  向消息队列投递一个 WM_QUIT 消息,促使 GetMessage 函数返回
0,结束消息循环 

    ::PostQuitMessage(0) ; 

    return 0 ; 

  } 

  //  将我们不处理的消息交给系统做默认处理 

  return ::DefWindowProc(hwnd, message, wParam, lParam); 

分析以上程序,可以得出在桌面上显示一个窗口的具体步骤,这就是主程序的结构流程。 

(1)注册窗口类(RegisterClassEx) 

(2)创建窗口(CreateWindowEx) 

(3)在桌面显示窗口(ShowWindow) 

(4)更新窗口客户区(UpdateWindow) 

(5)进入无限的消息获取和处理的循环。首先是获取消息(GetMessage),如果有消息到

达,则将消息分派到回调函数处理(DispatchMessage),如果消息是
WM_QUIT,则 GetMessage

函数返回 FALSE,整个消息循环结束。消息具体的处理过程是在 MainWndProc
函数中进行的。 

 

1.注册窗口类 

typedef struct _WNDCLASSEX {     

  UINT cbSize;          // WNDCLASSEX  结构的大小 

          UINT style;        //  从这个窗口类派生的窗口具有的风格 

          WNDPROC lpfnWndProc;    //  即  window procedure,  
 窗口消息处理函数指针 

          int cbClsExtra;          //
 指定紧跟在窗口类结构后的附加字节数 

          int cbWndExtra;        //  指定紧跟在窗口事例后的附加字节数 

          HANDLE hInstance;      //  本模块的实例句柄 

          HICON hIcon;        //  窗口左上角图标的句柄 

          HCURSOR hCursor;      //  光标的句柄 

          HBRUSH hbrBackground;  //  背景画刷的句柄 

          LPCTSTR lpszMenuName;    //  菜单名 

          LPCTSTR lpszClassName;      //  该窗口类的名称 

          HICON hIconSm;       //  小图标句柄   

} WNDCLASSEX; 

 

2.创建窗口 

HWND hwnd = ::CreateWindowEx(   

  0,            // dwExStyle,扩展样式   

  szClassName,        // lpClassName,类名       

  “My first Window!”,      // lpWindowName,标题     

  WS_OVERLAPPEDWINDOW,  // dwStyle,窗口风格   

  CW_USEDEFAULT,      // X,初始  X  坐标     

  CW_USEDEFAULT,      // Y,初始  Y  坐标     

  CW_USEDEFAULT,      // nWidth,宽度       

  CW_USEDEFAULT,      // nHeight,高度       

  NULL,          // hWndParent,父窗口句柄   

  NULL,          // hMenu,菜单句柄     

  hInstance,          // hlnstance,程序实例句柄     

  NULL) ;          // lpParam,用户数据     

下面列出了一些常见风格的定义,它们是以 WS(Windows  Style
的缩写)为前缀的预定

义的值: 

 WS_BORDER    创建一个单边框的窗口 

 WS_CAPTION    创建一个有标题框的窗口(包括 WS_BODER 风格) 

 WS_CHIlD    创建一个子窗口。这个风格不能与 WS_POPVP 风格合用 

 WS_DISABLED  
创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户

            的输人信息 

 WS_DLGFRAME
 创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条 

 WS_HSCROLL    创建一个有水平滚动条的窗口 

 WS_VSCROLL    创建一个有垂直滚动条的窗口 

 WS_ICONIC    创建一个初始状态为最小化状态的窗口。与 WS_MINIMIZE
风格相同 

 WS_MAXIMIZE  创建一个具有最大化按钮的窗口。该风格不能和
WS_EX_CONTEXTHELP 风

            格同时出现,同时必须指定 WS_SYSMENU 风格 

 WS_OVERLAPPED
 产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与  

            WS_TILED 风格相同 

 WS_OVERLAPPEDWINDOW  创建一个具有 WS_OVERLAPPED,WS_CAPTION,    

                WS_SYSMENU  ,WS_THICKFRAME,WS_MINIMIZEBOX, 

                WS_MAXMIZEBOX 风格的层叠窗口 

 WS_POPUP        创建一个弹出式窗口。该风格不能与 WS_CHLD
风格同时使用 

 WS_POPUPWINDOW    创建一个具有 WS_BORDER,WS_POPUP,WS_SYSMENU
风格的

                窗口,WS_CAPTION 和 WS_POPUPWINDOW 必须同时设定才能

                使窗口某单可见 

 WS_SIZEBOX        创建一个可调边框的窗口,与 WS_THICKFRAME 风格相同 

 WS_SYSMENU       创建一个在标题条上带有窗口菜单的窗口,必须同时设定   

                WS_CAPTION 风格 

 WS_THICKFRAME      创建一个具有可调边框的窗口,与 WS_SIZEBOX
风格相同 

 WS_VISIBLE              创建一个初始状态为可见的窗口 

 

typedef struct tagMSG { 

        HWND hwnd;    //  消息要发向的窗口句柄 

        UINT message;      //  消息标识符,以 WM_  开头的预定义值(意为
Window Message) 

        WPARAM wParam;        //  消息的参数之一 

        LPARAM lParam;    //  消息的参数之二 

        DWORD time;      //  消息放入消息队列的时间 

        POINT pt;        //  这是一个 POINT
 数据结构,表示消息放入消息队列时的鼠标位置 

  } MSG, *PMSG ; 

 

[cpp] view
plain copy

  函数调用成功将返回窗口句柄,失败返回NULL。第四个参数dwStyle的值是WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped
Window)。由它指定的窗口有标题栏、系统菜单、可以改变大小的边框,以及最大化、最小化和关闭按钮。这个一个标准窗口的样式。

  PS:

Visual C++
6.0,简称VC或者VC6.0,是微软推出的一款C++编译器,将“高级语言”翻译为“机器语言(低级语言)”的程序。Visual
C++是一个功能强大的可视化软件开发工具。自1993年Microsoft公司推出Visual
C++1.0后,随着其新版本的不断问世,Visual
C++已成为专业程序员进行软件开发的首选工具。虽然微软公司推出了 Visual
C++.NET(Visual C++7.0),但它的应用的很大的局限性,只适用于Windows
2000、Windows XP和Windows NT4.0。所以实际中,更多的是以Visual
C++6.0为平台。

  1. intAPIENTRY WinMain(HINSTANCE hInstance,  
  2.                      HINSTANCE hPrevInstance,  
  3.                      LPSTR lpCmdLine,  
  4.                      int nCmdShow)  
  5. {  
  6.     MSG msg;  //消息结构体  
  7.   
  8.     //向系统注册窗口类别,输入的参数“hInstance”是目前程序运个体的对象代码  
  9.   
  10.     MyRegisterClass(hInstance);    
  11.   
  12.     //运行初始化函数  
  13.   
  14.     if( ! InitInstance(hInstance,nCmdShow)   //InitInstance函数进行初始实例化操作  
  15.   
  16.     {  
  17.         return FALSE;  
  18.     }  
  19.   
  20.     while( GetMessage( &msg,NULL, 0, 0 ) )   //GetMessage函数从消息队列中抓取消息  
  21.     {  
  22.   
  23.          TranslateMessage(&msg);   //对键盘消息进行转换成系统消息  
  24.   
  25.          DispatchMessage(&msg);  //分派消息到WndProc函数给对应的消息处理函数处理  
  26.   
  27.     }  
  28.    return msg.wParam;   //退出时返回给操作系统的消息  
  29.   
  30. }  

3.  VC++6.0创建GUI程序:  1)创建VC++6.0,选择命令“文件”,点击“新建”;

1 ::PostQuitMessage(0);

Visual
C++它大概可以分成三个主要的部分:

 

     等等。

      第一个WM_PAINT消息被发送到窗口处理函数时,程序有机会向客户区画一些东西。

//程序入口

 

代码解释:

  1. ATMO MyRegisterClass( HINSTANCE hInstance )  
  2. {  
  3.      WNDCLASSEX wcex;  
  4.   
  5.      wcex.cbsize = sizeof(WNDCLASSEX);    //WNDCLASS所占用的内存字节  
  6.   
  7.      wcex.style = CS_HREARAW | CS_VREDRAW;   //窗体的样式  
  8.   
  9.      wcex.lpfnWndProc = (WNDPROC) WndProc;   //消息处理函数名,自己命名  
  10.   
  11.      wcex.cbClsExtra = 0;   //指定分配给窗口类结构(此处指lpszClassName)之后的额外字节数  
  12.   
  13.      wcex.cbWndExtra = 0;   //指定分配给窗口实例(此处指hInstance)之后的额外字节数  
  14.   
  15.      wcex.hInstance = hInstance;   //指定窗口过程所对应的实例句柄  
  16.   
  17.      wcex.hIcon =NULL;   //任务栏上的图标,NULL表示采用默认图标  
  18.   
  19.      wcex.hCursor = LoadCursor(NULL, IDC_ARROW);   //指定光标的样式  
  20.   
  21.      wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);   //指定窗口的背景画刷  
  22.   
  23.      wcex.lpszMenuName = NULL;      //通过菜单资源名称加载菜单  
  24.   
  25.      wcex.lpszClassName = “seekCName”;   //窗口类的类名(一个结构体而已,并不是C++的类)  
  26.   
  27.      wcex.hIconSm = NULL;   //窗口标题栏左侧的小图标,NULL表示采用默认图标  
  28.   
  29.    return RegisterClassEx(&wcex);  
  30.   
  31. }  

 *6.  处理消息:

  要创建窗口,用注册的窗口类的类名调用CreateWindowEx函数即可。

[cpp] view
plain copy

  调用BeginPaint函数后,主程序中调用了TextOut函数。

  如果指定窗口的更新区域不为空的话,UpdateWindow函数通过向这个窗口发送一个WM_PAINT消息更新它的客户区。当窗口显示在屏幕上时,窗口的客户区被在WNDCLASSEX中指定的刷子擦去了,调用UpdateWindow函数将促使客户区重画,以显示其内容。

//WndProc函数

  PS:

  PS:

 

  RegisterClassEx的唯一参数是这个结构的地址。注册窗口类后就可以将类名和其窗口函数、类的风格及其他的类属性联系起来。当进程在CreateWindowEx函数中指定一个类名的时候,系统就用这个窗口函数、风格和与此类名相关的其他属性创建窗口。

FirstWindow

 

1 ::ShowWindow(hwnd,nCmdShow);

  主程序中LoadIcon函数装载了一个预定义的图标(命名为IDI_APPLICATION),LoadCursor函数装载了一个预定义的光标(命名为IDC_ARROW)。如果要装载自定义的图标或光标的话,应该先向工程中添加一个资源脚本(后面打字程序将会提到),然后再通过菜单命令“Insert/Resource…”添加这些资源。

 

1 ::GetMessage(&msg,NULL,0,0);

        3)在桌面显示窗口(ShowWindow);

7.  系统为应用程序传递所有的输入到它的各个窗口,每个窗口都关联一个窗口函数,每当这个窗口有输入时,系统调用该函数。窗口函数处理输入,然后再将控制权交给系统。

6.  用户创建窗口后,就要对窗口的行为负责。当Windows向程序发送消息时,它调用程序中的一个函数,这个函数的参数精确地描述了Windows发送的消息。在程序中称这个函数为窗口函数(Window
Procedure)或消息处理函数。它是一个自定义的回调函数。

 

4.  Win32程序的入口函数将是WinMain函数,而不是控制台程序的main函数。

  ShowWindow函数用于设置指定窗口的显示状态,上面代码中的nCmdShow是系统传递给WinMain函数的参数。函数的第二个参数可以有多个不同的取值(具体情况请索引查看SDK文档),例如下面的代码将隐藏句柄hWnd指定的窗口。

[cpp] view
plain copy

  每当客户区变成无效,消息处理函数WndProc都会收到一个洗呢WM_PAINT消息。响应此消息的代码取得设备环境句柄后,再一次将szText的内容显示在指定位置。

 

       
UpdateWindow是在HDC上画图的(无论窗口隐藏与否),不是用来显示窗口的;

 

      在图形操作系统下,需要保存的数据太多了。同样地,Windows使这个窗口无效,窗口处理函数就会收到一个WM_PAINT消息,自己负责回复客户区内容。

//InitInstance函数

 

 

  1. LRESULT CALLBACK WndProc( HWND hWnd, UINT message,  
  2.                           WPARAM wParam, LPARAM lParam )  
  3. {  
  4.      PAINTSTRUCT ps;  
  5.       HDC hdc;  
  6.   
  7.       switch( message )  
  8.       {  
  9.              case WM_PAINT:   //窗口重绘消息  
  10.                   hdc = BeginPaint( hWnd, &ps );  
  11.                    //用hdc进行具体的绘图动作  
  12.                   EndPaint( hWnd, &ps );  
  13.                   break;  
  14.   
  15.              case WM_DESTROY:   //窗口结束消息  
  16.                   PostQuitMessage(0);  
  17.                   break;  
  18.   
  19.               default:  
  20.                   return DefWindowProc( hWnd, message, wParam, lParam );  //默认处理函数  
  21.      }  
  22.     retrun 0;  
  23.   
  24. }  

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图