入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

Window 32位 编程总结

创建时间:2017-05-07 投稿人: 浏览次数:863

Lesson01

win32
Window 32位 编程
1.Windows编程基础
2.Windows的字符
3.窗口处理
4.消息处理
5.绘图
6.对话框
7.控件

Win32编程:
Windows API:函数接口

一、Windows编程基础
1.Windows应用程序分类
1.1 控制台程序
DOS程序,本身没有窗口,通过WINDOWS下的DOS窗口执行。
1.2 窗口程序
拥有自己的窗口,通过窗口可以和用户进行交互
1.3 库程序
1.3.1 静态库程序
存放代码,数据的程序,其他执行文件从中获取数据和代码

    1.3.2 动态库程序
       存放代码,数据的程序,其他执行文件从中获取数据和代码       

2.对比
  2.1 入口函数
      控制台程序  - main
      窗口程序    - WinMain
      动态库程序  - DllMain
      静态库程序  - 无入口函数

  2.2 文件存在方式
      控制台程序  *.exe
      窗口程序    *.exe
      动态库程序  *.dll
      静态库程序  *.lib

  2.3 执行方式
     控制台程序  - 在DOS中执行
     窗口程序 - 拥有自己的窗口,在自己的窗口中执行
     动态库程序 - 本身无法执行,由其他可执行的程序(*.exe)或动态库(*.dll)调用
     静态库程序 - 执行不存在,嵌入其他可执行程序(.exe)或动态库中

二、Windows下得开发环境
1. Visual stdio C++ 6.0

     vc1.5-vc6.0(98前后)-vs2005-vs2008-vs2010-vs2013-vs2015

  2. win30-win31-win32-windows95-98-2000- xp|2003 server - vista|win7 | 2008 server
     - win8  - win10

  3.VC++编译工具
     1.编译器 CL.EXE
        将源代码编译成目标代码

     2. 链接器 LINK.EXE
        将目标代码,库文件链接生成最终文件

     3.资源管理器 RC.EXE            
        将资源编译,最终通过链接器存入最终文件      

   4.头文件
        windows.h  - 绝大多数头文件集合
        windef.h   - windows的数据类型
        winbase.h  - kernel32.dll的头文件
        wingdi.h   - gdi32.dll的头文件
        winuser.h  - user32.dll的头文件
        winnt.h    - 提供了UNICODE字符集的支持

   5. 库文件
        kernel32.dll   - 提供了核心的API,例如:进程、线程、内存管理等
        gdi32.dll      - 绘图相关的API
        user32.dll     - 提供窗口,消息API

三 Hello World 程序
int _tWinMain(HINSTANCE hInstance,
//应用程序实例句柄
HINSTANCE hPrevInstance,
//当前应用程序,前一个程序的实例句柄
LPTSTR lpCmdLine,
//命令行参数
int nCmdShow);
//显示方式

            hPrevInstance   - win32下一般为NULL,
             win32以前的程序用到的,现在一般不适用,历史遗留问题。


    int MessageBox(
        HWND hWnd,
        //父窗口句柄
        LPCTSTR lpText,
        //提示框中信息
        LPCTSTR lpCaption,
        //提示框标题栏的信息
        UINT uType
        //提示框的风格
    ); //返回的是点击按钮

Lesson02

         rc.exe

.rc ——————–>.res |
| link.exe
|——————->.exe/.lib/.dll(机器语言)
cl.exe |
.c/.cpp ——————–>汇编语言(.obj)|

   编译程序 - cl
     cl.exe /? 显示cl命令的帮助
            /c 只编译不链接

   链接程序 - link
      link.exe xxx.obj user32.lib uuid.lib

   执行看结果          

四、 第一个窗口程序
1.入口函数(WinMain)
2.定义窗口的处理函数 - 用于处理窗口中的各种消息
3.注册窗口类 - 将窗口类注册到系统中
4.创建窗口 - 将窗口创建(并未显示,在内存中创建窗口,内存中有了窗口的数据)
5.显示窗口 - 将窗口显示在显示器上(根据内存中的数据将窗口绘制出来)
6.消息循环 - 提取消息/翻译消息/派发消息
7.消息处理 - 在第2步中的窗口处理函数处理消息

Windows字符处理
  ASC        - 7位代表一个字符    128(0-127)
  ASCII      - 8位代表一个字符    256        前128与ASC相同 
                                         CODEPAGE  - 后面的128个分给其它国家语言使用
                                                汉语936  英语437

1.winodws字符的编码方式
   DBCS编码 (DOUBLE BYTE CHARACTER SET)
  由1个或2个字节表示一个字符
  A    我   是   程    序    员        
 01   0203 0405 0607  0809  0A0B
 0102 0304 0506 0708  090A  0B

 UNICODE编码(三套编码方式,他们分别是UTF-8 UTF-16 UTF-32)
 WINDOWS平台下,采用2个字节表示一个字符
 A    我   是   程    序    员  
0001 0203 0405 0607  0809  0A0B

Lesson03

2.字符的使用
   1.宽字节字符
     char       - 每一个字符占1个字节
     wchar_t    - 每一个字符占2个字节
     wchar_t    - 实际是unsigned short类型        
     定义时需要增加"L",通知编译器按照双字节编译字符串,采用
     UNICODE编码。函数需要使用支持宽字节字符串的函数 例如:
     wchar_t* wpszText = L"Hello WideChar";
     wprintf(L"%s",wprintf);
     int nlen = wcslen(wpszText);

   2.TCHAR:根据环境不同用UNICODE宏开关切换TCHAR的定义,
           如果定义了UNICODE那么TCHAR定义为wchar_t,如果
           没有定义UNICODE那么TCHAR定义为char

        #ifdef UNICODE              //#ifdef #ifndef 具有本文件内向上溯源性
        typedef wchar_t TCHAR,*PTHCAR;
        #define __TEXT(quote) L##quote     //L"HELLO"
        #else
        typedef char TCHAR,*PTCHAR;
        #define __TEXT(quote) quote
        #endif         

     TCHAR* pszText = __TEXT("HELLO");
     如果定义了UNICODE宏
     wchar_t* pszText = L"HELLO";
     如果没有定义UNICODE宏
     char* pszText = "HELLO";

    3.UNICODE字符打印
      wprintf 对UNICODE字符打印支持不完善

      在WINDOWS下使用WriteConsole
     BOOL WINAPI WriteConsole(
      _In_             HANDLE  hConsoleOutput,
      //标准输出句柄
      _In_       const VOID    *lpBuffer,
      //输出字符串的BUFF
      _In_             DWORD   nNumberOfCharsToWrite,
      //准备输出字符的个数
      _Out_            LPDWORD lpNumberOfCharsWritten,
      //实际输出字符格式
      _Reserved_       LPVOID  lpReserved
      //备用
    );

    获取标准句柄
    HANDLE GetStdHandle(
      DWORD nStdHandle
      //标准句柄类型
    ); //返回标准句柄

五、WINODWS窗口的注册和创建
1.窗口的创建过程
1.1 入口函数 -WinMain
1.2 定义窗口处理函数 -WindowProc
1.3 注册窗口类 -RegisterClass
1.4 创建窗口 -CreateWindow
1.5 显示窗口 -ShowWindow/UpateWindow
1.6 消息循环 -GetMessage/TranslateMessage/DispatchMessage
市场人员 需求分析师 调度/项目经理
1.7 消息处理

2.窗口类
  窗口类就是一个结构体,它包含了窗口各种参数信息的一个数据结构。
  每一个窗口必须有窗口类,基于窗口类,才可以创建窗口。

  每一个窗口都具有一个类名,使用前必须将类名注册到操作系统中

3.窗口类的分类
  3.1  系统窗口类           - 系统已定义好的窗口类,所有程序无须注册,直接使用即可。
  3.2  应用程序全局窗口类   - 由用户自己定义,当前应用程序的所有模块均可以使用      
  3.3  应用程序局部窗口类   - 由用户自己定义,当前应用程序的本模块可以使用 

4.系统窗口类的使用
  不需要注册(不需要使用RegisterClass)直接使用系统以及定义好的窗口类名称即可。
  比如:"BUTTON"   - 按钮
        "EDIT"     - 文本编辑框  

5.应用程序全局窗口类的使用
   5.1 注册窗口类
       RegisterClass/RegisterClassEx

      WNDCLASSEX 结构体
    typedef struct tagWNDCLASSEX {
              UINT      cbSize;         //结构体的大小, sizeof(WNDCLASSEX)
              UINT      style;          //窗口风格 
              WNDPROC   lpfnWndProc;    //窗口处理函数
              int       cbClsExtra;     //窗口类附加数据缓冲区大小,字节为单位 
              int       cbWndExtra;     //窗口的附加数据,字节为单位
              HINSTANCE hInstance;      //应用程序实例句柄
              HICON     hIcon;          //窗口大图标句柄
              HCURSOR   hCursor;        //鼠标光标
              HBRUSH    hbrBackground;  //窗口背景颜色
              LPCTSTR   lpszMenuName;   //菜单
              LPCTSTR   lpszClassName;  //窗口类名称(最好不是汉语)
              HICON     hIconSm;        //窗口的小图标
            } WNDCLASSEX, *PWNDCLASSEX;

    应用程序全局窗口类,在注册时需要增加CS_GLOBALCLASS 例如:
    WNDCLASSEX wce = {0};
    wce.style = ....|CS_GLOBALCLASS;

6. 应用程序局部窗口类
    在注册使用,不添加CS_GLOBALCLASS风格

7. 窗口类的风格       
    CS_GLOBALCLASS   - 应用程序全局窗口类(一般不用)
    CS_BYTEALIGNCLIENT - 窗口客户区水平位置8
                   倍数对齐。
    CS_BYTEALIGNWINDOW - 窗口水平位置8倍数对齐
    CS_HREDRAW - 窗口水平位置移动,重绘窗口。
    CS_VREDRAW - 窗口垂直位置移动,重绘窗口。
    CS_CLASSDC - 该类型窗口,都使用同一个DC.
    CS_PARENTDC - 该类型窗口,使用父窗口的DC.
    CS_OWNDC - 该类型窗口,使用自己的DC.
    CS_SAVEBITS - 允许窗口保存成位图(BMP)
    CS_DBLCLKS - 允许窗口接收鼠标双击消息。
    CS_NOCLOSE - 窗口没有关闭按钮。

Lesson04
8. 窗口类的查找过程
1. 系统会根据传入的窗口类名,在应用程序局部窗口类中查找。
如果找到了执行2
如果未找到执行3

   2.比较局部窗口类与窗口窗口时传入的HINSTANCE变量。
     如果发现相等,创建和注册在同一模块中,创建窗口并返回
     如果发现不相等继续执行3

   3.在应用程序全局窗口类中查找。
     如果找到执行4  
     如果未找到执行5

   4.使用找到的窗口类,创建窗口,并返回。

   5.在系统窗口类中查找,
    如果找到创建窗口并返回,
    如果未找到创建窗口失败

六。创建窗口
CreateWindow/CreateWindowEx
HWND WINAPI CreateWindowEx(
In DWORD dwExStyle,
//窗口的拓展风格
In_opt LPCTSTR lpClassName,
//窗口类名
In_opt LPCTSTR lpWindowName,
//窗口标题名称名
In DWORD dwStyle,
//窗口的风格
In int x,
//窗口左上角的x坐轴标
In int y,
//窗口左上角的y坐轴标
In int nWidth,
//窗口的宽度
In int nHeight,
//窗口的高度
In_opt HWND hWndParent,
//父窗口句柄
In_opt HMENU hMenu,
//窗口的菜单句柄
In_opt HINSTANCE hInstance,
//应用程序实例句柄
In_opt LPVOID lpParam
//窗口创建时的附加数据(参数)
); //执行成功,返回窗口句柄

2 子窗口的创建
2.1 创建时要设置父窗口句柄
2.2 创建子窗口要设置WS_CHILD | WS_VISIBLE

3 窗口类和窗口的附加数据
int cbClsExtra; //窗口类附加数据的BUFF大小,建议是4的倍数
int cbWndExtra; //窗口附加数据BUFF大小,建议是4的倍数

 SetClassLong    //设置窗口类附加数据
 DWORD WINAPI SetClassLong(
  _In_ HWND hWnd,      //窗口句柄
  _In_ int  nIndex,    //0-? 内存索引 
  _In_ LONG dwNewLong  //要设置的数据 (4字节)
 );

 GetClassLong    //获取窗口类附加数据
 DWORD WINAPI GetClassLong(
  _In_ HWND hWnd,
  _In_ int  nIndex
);//返回设置的附加数据

 SetWindowLong  //设置窗口附加数据    
 LONG WINAPI SetWindowLong(
  _In_ HWND hWnd,
  _In_ int  nIndex,
  _In_ LONG dwNewLong
);

GetWindowLong   //获取窗口附加数据
LONG WINAPI GetWindowLong(
  _In_ HWND hWnd,
  _In_ int  nIndex
);  
可以提供窗口类和窗口存放自己数据空间,基本不用

七 消息机制
1.程序的执行机制
过程驱动 - 程序的执行过程按照事先安排好的顺序执行

 事件驱动    - 程序的执行时无序的,用户可以根据需要随机
               触发相应的事件

 win32 窗口程序采用的事件驱动方式也就是消息机制                


2.消息机制
   当系统通知窗口工作时,就是采用消息的范式派发给窗口
   2.1 消息的定义
       每个消息都有一个ID,同时还附带了两个消息的参数
        typedef struct tagMSG {
            HWND        hwnd;     //窗口的句柄
            UINT        message;  //消息的ID 
            WPARAM      wParam;   //消息的附加数据1
            LPARAM      lParam;   //消息的附加数据2
            DWORD       time;     //消息产生的时间
            POINT       pt;       //消息产生时鼠标的位置
        } MSG;     

   2.2 窗口处理函数
      LRESULT CALLBACK WndProc(
        HWND hWnd,      //窗口句柄
        UINT nMsg,      //消息ID
        WPARAM wParam,  //消息附加参数1
        LPARAM lParam)  //消息附加参数2

     当系统通知窗口时,会调用窗口处理函数,同时将
     消息的ID和参数传递给窗口处理函数。
     在窗口处理函数中,不处理的消息调用缺省处理函数
     DefWindowProc

   2.3 消息相关的函数
     2.3.1 GetMessage        - 获取消息
        BOOL WINAPI GetMessage(
          _Out_    LPMSG lpMsg,         //获取的消息的BUFF
          _In_opt_ HWND  hWnd,          //窗口句柄
          _In_     UINT  wMsgFilterMin, //获取的消息最小ID
          _In_     UINT  wMsgFilterMax  //获取的消息最大ID
        );

        wMsgFilterMin和wMsgFilterMax只能获取由这两个值,指定的消息
        范围,如果都为0,表示没有范围

     2.3.2 TranslateMessage  - 翻译消息
         将按键消息(可以字符的按键消息需要翻译),翻译成字符消息
         BOOL TranslateMessage(
                CONST MSG* lpMsg
                    //要翻译的消息的地址
                );
          首先检查是否是可见字符的按键消息,如果不是,直接返回

     2.3.3 DispatchMessage - 派发消息
          LONG DispatchMessage(
                CONST MSG* lpMsg
                //准备派发的消息的地址
                ); 

Lesson05
3 常见的几个消息
3.1 WM_DESTROY -窗口销毁时的消息
无消息参数,常见与窗口销毁之前的善后处理,例如:资源,内存的回收等

    3.2 WM_SYSCOMMAND  -系统命令消息   
           当点击 最小化/最大化/关闭按钮等命令时,收到消息。常用于才窗口关闭时,
         提示用户处理
        WPARMA     - 具体的命令,例如:SC_CLOSE

        LPARAM
        LOWORD     - 鼠标的X轴坐标
        HIWORD     - 鼠标的Y轴坐标
        低两个字节:  int a = 10000;
                     short b = a & 0xffff;          
        高两个字节: short c = a>>16;

    3.3 WM_CREATE      -窗口创建成功但还未显示之前
                  常见于窗口的参数初始化,资源创建包括子窗口的创建
        WPARAM   - 不使用
        LPARAM   - 是CREATESTRUCT结构体的指针,保存了CreateWindowEx函数的12个参数


    3.4 WM_SIZE       -窗口的大小发生变化后,收到这个消息
                   常用于窗口大小变化后,调整窗口内的布局
           WPARAM    - 窗口大小变化的原因
           LPARAM    
             LOWORD  - 窗口大小变化后客户区的宽度
             HIWORD  - 窗口大小变化后客户区的高度

   3.5  WM_QUIT      - 用于结束消息循环
          WPARAM     -退出码,PostQuitMessage函数的参数指定
          LPARAM     -不使用
        当GetMessage收到这个消息后,会返回FALSE,结束while循环(使消息循环退出)
        该消息不会出现在窗口处理函数中


4. 消息的获取和发送
     4.1 消息的获取
        GetMessage    - 从系统中获取消息,将消息从系统中移除,阻塞函数,当系统
                         中没有消息,这个函数阻塞等候下一条消息。

        PeekMessage   - 已查看的方式从系统获取消息,可以不将消息移除,非阻塞函数

         BOOL WINAPI PeekMessage(
          _Out_    LPMSG lpMsg,
          _In_opt_ HWND  hWnd,
          _In_     UINT  wMsgFilterMin,
          _In_     UINT  wMsgFilterMax,
          _In_     UINT  wRemoveMsg
           //移除表示
        );

     4.2 消息发送
      BOOL WINAPI PostMessage(
          _In_opt_ HWND   hWnd,
          //窗口句柄
          _In_     UINT   Msg,
          //消息ID
          _In_     WPARAM wParam,
          //消息参数1
          _In_     LPARAM lParam
          //消息参数2
        );   

       PostMessage   -投递消息,消息发出去后立即返回,不等候消息的处理结果


        LRESULT WINAPI SendMessage(
          _In_ HWND   hWnd,
          _In_ UINT   Msg,
          _In_ WPARAM wParam,
          _In_ LPARAM lParam
        );

        SendMessage   -发送消息,消息发出去后,等候处理完,才返回.


5. 消息的分类
    1. 系统消息          - ID范围(0-0x0FF) 1024
      由系统定义好的消息,所有程序直接可以使用

    2.用户自定义消息     - ID范围(0x0400-0x7FFF)(31743)
      由用户自己定义,满足用户自己的需求,用户自定义的消息,需要用户自己
      发送,并负责处理
          定义宏 WM_USER 代表0x0400,自定义消息ID时
          #define  WM_MYMESSAGE  WM_USER+n

    3.应用程序消息      - ID范围(0x8000 - 0xBFFF)
      用于程序之间的通信(目前用不到,多见底层驱动程序)
       定义宏 WM_APP 代表0x8000


    4.系统注册消息     - ID范围(0xC000-0xFFFF)
      在系统注册并生成消息,然后在各个应用程序中使用

八. 消息和消息队列
1. 消息队列
用于存放消息的队列,消息在队列中先进先出,所有窗口都有消息队列,程序从消息队列
中提出消息

  2. 消息队列的类型         
     2.1 系统的消息队列
         由系统维护的消息队列,存放系统产生的消息。(鼠标,键盘)

     2.2 程序的消息队列
         属于程序(主线程)的消息队列,由程序本身负责维护。       


  3.消息队列的关系 
     3.1 当鼠标和键盘产生消息时,先放入系统消息队列

     3.2 系统会根据存放消息,找到对应的窗口信息

     3.3 按照对应的窗口信息,将消息转发给相应的进程的消息队列中


  4.队列消息和非队列消息
     4.1 根据消息和消息队列的使用关系
        4.1.1 队列消息
            将消息存入消息队列,消息的发送和获取都是通过队列完成

        4.1.2 非队列消息             
             消息不进入队列,直接调用窗口处理函数

     4.2 队列消息 
         - 先把消息放入队列,通过消息循环从队列中获取消息并且发送给窗口处理函数

         GetMessage/PeekMessage    -取队列消息
         PostMessage               -向队列中投递消息


     4.3 非队列消息
         - 消息直接找对应的窗口处理函数,并调用处理函数,完成处理

         SendMessage   -  发送非队列消息,直接窗口处理函数,等待处理结果。

         SendMessage(...)
         {
            //...
            return WndProc(...);
         }      

Lesson 6
5 消息的获取
5.1.1 消息循环
5.1.1 GetMessage/PeekMessage 从程序的消息队列中获取消息

      5.1.2 TranslateMessage   
      -检查GetMessage/PeekMessage函数获取到的消息,
       如果是可见字符按键消息,产生一个字符消息(WM_CHAR),并且将
       字符消息放入消息队列

      5.1.3 DispatchMessage   
       -根据取出的消息,找到对应的窗口处理函数,
        完成消息处理

  5.2  GetMessage/PeekMessage 执行机制
       1 先去程序(线程)的消息队列中检查有没有消息,
          如果有消息,检查指定条件(窗口句柄,ID范围)是否满足,如果满足
          条件取出消息进行处理

       2 如果程序(线程)的消息队列中没有消息,向系统的消息队列中获取本程序的
          消息,系统将消息转发给程序的消息队列,然后GetMessage/PeekMessage再从
          程序的消息队列中获取消息
          (系统队列中的消息无法直接获取,需要转发到程序的消息队列中在获取)

       3  如果系统的消息队列中也没有和本程序相关的消息,检查有没有需要重新绘制的
          区域,如果有发送WM_PAINT 消息,放入队列,取出并处理

       4  如果没有需要重新绘制的区域,检查有没有到时间的定时器,如果有发送WM_TIMER消息
          放入队列,取出并处理

       5  如果以上都没有,整理内存和资源等

       6  GetMessage 阻塞等候下一条消息
          PeeKMessage 会返回FALSE,交出程序的控制权

          注:GetMessage函数,如果获取到WM_QUIT 返回FALSE

九、WM_PAINT

 1. WM_PAINT    - 窗口中,有需要重新回去的区域,就会产生WM_PAINT消息

 窗口需要重新绘制的区域叫窗口无效区域

 UpdateWindow/RedrawWindow 刷新整个窗口
 BOOL InvalidateRect(
  _In_       HWND hWnd,   //窗口句柄
  _In_ const RECT *lpRect,//定义窗口无效区域(可以为NULL)
  _In_       BOOL bErase  //擦除标识
);             

2. 绘图步骤(WM_PAINT)
  2.1 BeginPaint    -开始绘图
  HDC BeginPaint(
   _In_  HWND          hwnd,   //窗口句柄
   _Out_ LPPAINTSTRUCT lpPaint //绘图结构体指针(程序员基本不用)
 ); //返回绘图设备句柄


 2.2 绘图(需要使用HDC)

 2.3 EndPaint     -结束绘图

 BOOL EndPaint(
  _In_       HWND        hWnd, //窗口句柄
  _In_ const PAINTSTRUCT *lpPaint //绘图结构体指针(程序员基本不用)
 );


 WM_PAINT的处理过程:
    如果有无效区域(无效区域标识),再合适的时机产生WM_PAINT消息,在处理
    函数中对这个消息进行处理,处理时先调用BeginPaint(...),得到绘图设备句柄
    的同时去掉无效区域标识,然后用HDC完成绘图,最后利用EndPaint结束绘图

十 键盘消息
WM_KEYDOWN -按键按下时产生的消息(按住不松可以产生多次WM_KEYDOWN)
WM_KEYUP -按键被放开产生的消息 (一次按键只能产生一次)
WPARAM -虚拟键码
LPARAM -按键的参数,比如按键的次数等

WM_CHAR       -字符消息 (TranslateMessage)
    WPARAM    - 字符编码
    LPARAM    - 按键的参数

    TranslateMessage(&nMsg)
    {
        //是否是按键消息
        if (nMsg.message != WM_KEYDOWN )
            return;

        //通过nMsg.wParam(虚拟键码)判断是否是可见字符
        if ( 不是可见字符)
            return;

        if(是可见字符)
        {
            //判断capslock是否处于打开状态
            if(打开)
                ...
                PostMessage(nMsg.hWnd,WM_CHAR,0x41,...);
            else
                ...
                PostMessage(nMsg.hWnd,WM_CHAR,0x61,...);
        }           
    }       

 WM_KEYDOWN/UP按键消息的WPARAM 表示按键的虚拟键码

 WM_CHAR字符消息的WPARAM 表示的是输入字符(字符ASCII编码)  

六 鼠标消息
1.鼠标基本消息
鼠标左键按下 - WM_LBUTTONDOWN
鼠标左键弹起 - WM_LBUTTONUP
鼠标右键按下 - WM_RBUTTONDOWN
鼠标右键弹起 - WM_RBUTTONUP
鼠标移动 - WM_MOUSEMOVE
WPARAM -按键的状态 例如:Ctrl/Shift
LPARAM
LOWORD -鼠标光标的x轴坐标(客户区坐标系)
HIWORD -鼠标光标的y轴坐标

Lesson 7

  1. 双击消息 需要CS_DBLCLKS风格
    鼠标左键双击 - WM_LBUTTONDBLCLK
    鼠标右键双击 - WM_RBUTTONDBLCLK
    WPARAM -按键的状态 例如:Ctrl/Shift
    LPARAM
    LOWORD -鼠标光标的x轴坐标
    HIWORD -鼠标光标的y轴坐标

  2. 鼠标滚轮消息 - WM_MOUSEWHEEL
    WPARAM
    LOWORD -按键的状态 例如:Ctrl/Shift
    HIWORD -滚轮滚动偏移量(120倍数)
    正数代表向前滚,负数代表向后滚

     LPARAM       鼠标当前位置,屏幕坐标系
         LOWORD   -鼠标光标的x轴坐标
         HIWORD   -鼠标光标的y轴坐标
    

七 定时器Timer (WM_TIMER)
1.可以在程序中设置定时器,每隔一定的时间间隔会向
消息队列中发送一个WM_TIMER消息。

  定时器时间间隔的单位毫秒 但是准确率很差 

  每隔一定时间间隔,自动发送WM_TIMER消息到窗口处理函数,
  间隔单位毫秒,但不是一个准确的定时器,而且由于优先级较低
  有可能根本不产生。   

2.消息的参数
  WPARAM  - 定时器ID
  LPARAM  - 定时器处理函数的指针

3.定时器的使用
   3.1 创建并启动定时器
     UINT WINAPI SetTimer(
       HWND      hWnd,
       //窗口句柄
       UINT_PTR  nIDEvent,
       //定时器ID
       UINT      uElapse,
       //定时器的时间间隔(ms)
       TIMERPROC lpTimerFunc
       //定时器的处理函数(可以为NULL)
    );//如果定时器创建成功,返回非0

  定时器的处理函数可以自己定义,也可以使用窗口处理函数

  3.2 定时器处理函数
     VOID CALLBACK TimerProc(
       HWND     hwnd,
       //窗口句柄
       UINT     uMsg,
       //WM_TIMER
       UINT_PTR idEvent,
       //定时器ID
       DWORD    dwTime
       //当前系统时间
    );


  3.3 定时器每隔uElapse 毫秒产生一个WM_TIMER消息,这个消息将由
      TimerProc或者WindowsProc来处理   

  3.4 关闭定时器
     KillTimer   -销毁定时器
    BOOL KillTimer(
      HWND hWnd, 
      //窗口句柄
      UINT uIDEvent
      //定时器ID         
    ); 

练习:
GetClientRect -得到窗口客户区的大小
BOOL WINAPI GetClientRect(
HWND hWnd,
//窗口句柄
LPRECT lpRect
//RECT结构体的指针
);

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


  Ellipse    -绘制圆
     BOOL Ellipse(
         HDC hdc,
         //绘图设备句柄(BeginPaint函数的返回值)
         int nLeftRect,
         //左上角的X坐标       
         int nTopRect,
         //左上角的Y坐标       
         int nRightRect,
         //右下角的X坐标       
         int nBottomRect
         //右下角的Y坐标
     );

Lesson8
八.菜单的分类
1.1 窗口顶层菜单
1.2 弹出式菜单
1.3 系统菜单
HMENU - 菜单句柄
每一个参与消息的菜单项都对应一个ID

2.窗口顶层菜单
    2.1 CreateMenu     -创建菜单      
        HMENU WINAPI CreateMenu(); 

    2.2 AppendMenu/InsertMenu   - 添加菜单项        
        BOOL WINAPI AppendMenu(
           HMENU    hMenu,
           //菜单句柄
           UINT     uFlags,
           //菜单项的风格
           UINT_PTR uIDNewItem,
           //菜单的ID或者(弹出式)下拉菜单的句柄
           LPCTSTR  lpNewItem
           //菜单项的文字信息
        );

    uFlags:
    MF_POPUP       - 菜单项要有弹出式菜单,菜单项id为(弹出式)下拉菜单(子菜单)的句柄     
    MF_SEPARATOR   - 菜单项分割线
    MF_STRING      - 菜单被点击之后,发出消息WM_COMMAND
    MF_MENUBARBREAK  -对于弹出式菜单,放到新栏中,栏间有分隔线          

    2.3 显示菜单
    BOOL WINAPI SetMenu(
           HWND  hWnd,
           //窗口句柄
           HMENU hMenu
           //菜单句柄
    );

3. 弹出式菜单
   3.1  CreatePopupMenu   - 创建弹出式菜单
           HMENU WINAPI CreatePopupMenu();

   3.2  AppendMenu/InsertMenu   -添加菜单项


4. 菜单项的消息
    点击菜单项产生WM_COMMAND消息
    WPARAM
        HIWORD    - 对于菜单为0
        LOWORD    - 指明被点击的菜单项的ID

    LPARAM     -对于菜单为NULL

  可以根据LOWORD(wParam)确定菜单项的ID,然后根据ID处理消息


5. 菜单的状态
   5.1 在增加菜单项时,设置菜单项的状态MF_XXX(如:MF_CHECKED MF_GRAYED)
   5.2 可以使用特定的函数改变菜单项的状态
       5.2.1 CheckMenuItem        -修改勾选状态
         DWORD CheckMenuItem(
            HMENU hmenu, 
            //菜单的句柄
            UINT uIDCheckItem,
            //菜单项的ID(或者索引)
            UINT uCheck
            //菜单项的状态
        );

       5.2.2 EnableMenuItem      -修改可用状态     
         DWORD EnableMenuItem(
            HMENU hmenu, 
            //菜单的句柄
            UINT uIDCheckItem,
            //菜单项的ID(或者索引)
            UINT uCheck
            //菜单项的状态
        );

       注:分割线占一个位置
       以上两个函数,再使用时,菜单项标识
       可以使用位置(索引)或者ID
       MF_BYCOMMAND 通过id定位  
       MF_BYPOSITION 通过位置索引

    5.3 WM_INITMENUPOPUP
         在菜单被激活但还未显示之前,产生的消息

        WPARAM      - 菜单句柄(弹出即将显示的菜单句柄) 

        LPARAM
             LOWORD  - 被点击的顶层菜单项的位置(索引)
             HIWORD  - 窗口菜单的标识

        窗口菜单:系统菜单和窗口的顶层菜单
        弹出式菜单不属于窗口菜单

6. 系统菜单
   1.  GetSystemMenu   - 获取系统菜单句柄
       HMENU WINAPI GetSystemMenu(
           HWND hWnd,
           //窗口句柄
           BOOL bRevert
           //重置标识
        );

        TRUE:  把当前的系统菜单重置为默认的系统菜单
        FLASE: 不做重置,返回当前的系统菜单句柄

   2. 系统菜单的修改
        BOOL DeleteMenu( 
            HMENU hMenu,
            //菜单句柄
            UINT uPosition,
            //菜单的ID或者位置(索引)
            UINT uFlags
            //MF_BYCOMMAND/MF_BYPOSITION
         );

        AppendMenu           

   3. 系统菜单的消息
      WM_SYSCOMMAND
        WPARAM  
          LOWORD   菜单项的ID


7. 右键弹出菜单
   1.使用
      1.1 创建弹出菜单 CreatePopupMenu
          AppenMenu/InsertMenu

      1.2 显示弹出式菜单 TrackPopupMenu              
        BOOL WINAPI TrackPopupMenu(
         HMENU hMenu,
         //弹出式菜单句柄
         UINT  uFlags,
         //菜单风格
         int   x,
         //菜单x轴位置 (屏幕坐标)
         int   y,
         //菜单y轴位置 (屏幕坐标)
         int   nReserved,
         //保留参数,必须为0
         HWND  hWnd,
         //窗口句柄
         const RECT  *prcRect
         //忽略
    );

    TrackPopupMenu 是一个阻塞函数,在选择菜单项之前程序不会继续执行

    窗口(客户区)坐标转换屏幕坐标
    ClientToScreen
    BOOL ClientToScreen( 
      HWND hWnd, 
      //窗口句柄
      LPPOINT lpPoint
      //点的坐标(输入输出参数)
      客户区坐标系下的坐标
      屏幕坐标系下的坐标
    ); 

    屏幕坐标转换成窗口客户区坐标
    ScreentToClient
    BOOL ClientToScreen( 
      HWND hWnd, 
      //窗口句柄
      LPPOINT lpPoint
      //点的坐标(输入输出参数)
      屏幕坐标系下的坐标
      客户区坐标系下的坐标
    ); 

    1.3 菜单项的命令处理
        WM_COMMAND 与窗口顶层菜单一样

    1.4 WM_CONTEXTMENU专职处理右键菜单,在WM_RBUTTONUP之后产生
        WPARAM      -指向窗口句柄
        LPARAM 
           LOWORD    -光标的x轴坐标(屏幕坐标系)
           HIWORD    -光标的y轴坐标(屏幕坐标系)

Lesson 9

九、资源的使用
1. 资源相关
资源脚本文件 .rc文件
rc.exe 将.rc文件编译生成.res文件
资源可以给程序设定菜单、工具栏、快捷键、位图、对话框、
程序版本信息、多种语言的STRING表等…

      注:使用资源必须建立.rc(资源)脚本文件


    2.菜单资源的使用
      2.1 添加菜单资源(VS中添加)

      2.2 使用菜单资源
         2.2.1 注册窗口类时加载菜单          基于窗口类创建的所有窗口菜单都一样
           MAKEINTRESOURCE       - 将数字形式的资源ID转换为字符串形式的资源ID
           MAKEINTRESOURCE(IDR_MENU1)

         2.2.2 加载菜单资源,设置到窗口      基于同一窗口类可以挂载不同的菜单
            HMENU LoadMenu( 
              HINSTANCE hInstance,
              //应用程序实例句柄
              LPCTSTR lpMenuName
             //字符串形式的菜单资源ID
             (利用MAKEINTRESOURCE转换)
            ); 
            将硬盘上的.rc脚本文件中关于lpMenuName资源的数据加载到hInstance指明的内存中,
            并获取菜单句柄

    3.图标资源的使用
      3.1 添加图标资源(VS中添加)

      3.2 使用图标资源,加载图标   
            HICON LoadIcon( 
              HINSTANCE hInstance,
               //应用程序实例句柄
              LPCTSTR lpIconName
             //字符串形式的菜单资源ID
             (利用MAKEINTRESOURCE转换)                
            ); 
      3.3 设置图标  
          3.3.1 注册窗口类时,设置图标
             建议大小图标一致,用户体验好


          3.3.2 使用WM_SETICON消息
              wParam = (WPARAM)(BOOL) fType;
                   ICON_BIG/ICON_SMALL  大图标/小图标

             lParam = (LPARAM)(HICON) hicon;
                   要设置的图标的句柄                 

       3.4 绘制图标到窗口
            BOOL DrawIcon(
                HDC hDC,
                //绘图设备句柄
                int X,
                //x轴坐标(客户区坐标系)
                int Y, 
                //y轴坐标(客户区坐标系)
                HICON hlcon 
                //图标句柄
            );


    4. 光标资源的使用  
        4.1 在VS中添加
         光标的大小默认是32*32像素,每个光标都有HotSpot,是当前鼠标的热点

         Windows下光标的文件.cur(静态)为后缀和.ani(动态)为后缀
         系统光标目录:C:WindowsCursors

        4.2 加载光标资源
            HCURSOR WINAPI LoadCursor(
               HINSTANCE hInstance,
                //应用程序实例句柄
               LPCTSTR   lpCursorName
               //字符串形式的菜单资源ID
              (利用MAKEINTRESOURCE转换) 
            );

            4.2.1 注册窗口类时


            4.2.2 使用SetCursor设置光标
                HCURSOR SetCursor(
                  HCURSOR hCursor
                  //设置的新的光标句柄
                );//返回原来的光标句柄

        4.3  WM_SETCURSOR 消息
           产生: 鼠标移动导致光标的移动,并且捕获鼠标的移动,就产生WM_SETCURSOR
           WPARAM     -当前使用的光标句柄

           LPARAM
              LOWORD     - 当前区域的代码(hit-test code)
                        (HTCLIENT 代表客户区  HTCAPTION 非客户区-标题栏)

              HIWORD     - 当前鼠标消息ID             


            GetCursorPos    - 得到鼠标光标位置
            BOOL WINAPI GetCursorPos(
              LPPOINT lpPoint
              //存放鼠标位置buffer,屏幕坐标系下的坐标
            );

            GetClientRect      -获取窗口边界,窗口客气区坐标系
            ScreenToClient    -将屏幕坐标系下的坐标转换为客户区坐标系下的坐标


            从光标文件中加载光标资源
            HCURSOR LoadCursorFromFile(
            LPCTSTR IpFileName
             //光标资源文件名
            );

Lesson10

  5. 字符串资源
    2.1 添加字符串资源
       字符串表,在表中添加字符串

    2.2  字符串资源的使用   
      int LoadString( 
          HINSTANCE hInstance,
            //应用程序实例句柄
          UINT uID,  
           //资源ID
          LPTSTR lpBuffer,
            //接收字符串的BUFF
          int cchBufferMax 
           //BUFF的大小          
        ); //成功返回字符窗的长度,失败返回0


  6 快捷键(加速键)资源
     6.1 添加快捷键资源
        添加加速键表,增加命令ID对应的加速键
        一般加速键可以和菜单项的ID命令对应


     6.2 快捷键(加速键)的使用         
           6.2.1 加载快捷键(加速表)表
              HACCEL LoadAccelerators(
                  HINSTANCE hInstance,
                   //应用程序实例句柄
                  LPCTSTR lpTableName
                   //字符串形式的加速键资源ID                    
                ); //返回加速键句柄


            6.2.2 处理加速键消息
              int TranslateAccelerator(
                  HWND hWnd, 
                  //窗口句柄
                  HACCEL hAccTable,
                  //加速键表句柄
                  LPMSG lpMsg
                  //消息
                ); //如果是加速键返回非0


            6.2.3 TranslateAccelerator 函数的执行机制

                 TranslateAccelerator(hwnd,hAccTable,&nMsg)
                 {
                    if ( nMsg.message != WM_KEYDOWN || nMsg.message != WM_SYSCOMMAND )
                        return 0;

                    根据消息附带的参数(nMsg.wParam)虚拟键码(CTRL+Y)

                    将(CTRL+Y)去hAccTable加速键表中查找

                    if(找到了)
                    {
                        PostMessage(hwnd,WM_COMMAND, L(ID_NEW) H(1),NULL);
                        return 1;
                    }else{
                        return 0;
                    }
                 }


            6.2.4 快捷键(加速键)产生WM_COMMAND   
                 WPARAM
                   HIWORD      - 加速键为1           菜单为0                    
                   LOWORD      - 加速键ID            菜单的ID

                 LPARAM  -未使用


            6.2.5 加速键的命令ID与菜单项的命令ID无关
                  但是为了代码复用最好定义成一样的ID

十、绘图
1. 绘图相关
绘图设备 (Device Context - DC 也叫绘图上下文)

       BeginPaint   - 获取绘图设备

          HDC hdc = BeginPaint(hWnd,...);
          TextOut(hdc,100,100,"dfsass",...);
          Ellipse(hdc,100,100,200,200,...);

       EndPaint  - 回收绘图设备

       HDC   -DC句柄  表示绘图设备

  2. GDI  -windows graphics device interface  WIN32提供的绘图API            


  3. 颜色
      3.1 颜色的表示(RGB)
          计算机使用红,绿,蓝每种颜色的取值范围
            R 代表红色   0 ~ 255
            G 代表绿色   0 ~ 255
            B 代表蓝色   0 ~ 255               

          每个点的颜色是3个字节(24位)保存取值范围(0 ~ 2^24 - 1)

                R    G    B
         16位   5    5    6
         32位   8    8    8  多出的8位用于透明度(一般是3D绘图用) 

         Direct3D
         openGL          


      3.2 颜色的使用
            COLORREF      -实际是DWORD
            COLORREF nColor = 255;

            赋值使用RGB宏,例如:
            COLORREF nColor = RGB(0,255,0);

            获取颜色的RGB值
            GetRValue(nColor)/GetGValue/GetBValue
              例如: BYTE nRed = GetRValue(nColor);


      3.3 点的使用
          GetPixel    - 获取指定点的颜色 

          COLORREF GetPixel(
              HDC hdc,
              //绘图设备句柄      
              int nXPos, 
              //x轴坐标
              int nYPos
              //x轴坐标
           ); 


           SetPixel    - 设置指定点的颜色
           COLORREF SetPixel(
              HDC hdc, 
               //绘图设备句柄 
              int X, 
              //x轴坐标
              int Y, 
              //x轴坐标
              COLORREF crColor
              //设置的颜色值
            ); 


     3.4 线的使用
           MoveToEx      - 移动当前点到指定点(指定线的初始点)

            BOOL  MoveToEx(
                HDC hdc,
                //DC句柄
                int X,
                //指定点的x坐标
                int Y,
                //指定点的y坐标
                LPPOINT lpPoint
                //当期点的BUFF
                );


            LineTo  - 从当前点到终点绘制一条直线

          BOOL LineTo(
              HDC hdc,
              //DC句柄
              int nXEnd,
              //指定终点的x坐标
              int nYEnd
              //指定终点的y坐标
            );      


           默认情况下,当前为(0,0), 上一次绘图的终点是下一次绘图的当前点


    3.5 封闭图形的使用( 能够用画刷填充的图形 ?)
         Rectangle/RoundRect


         BOOL Rectangle(
                HDC hdc, //DC句柄
                int nLeftRect, //左上角的x坐标
                int nTopRect,  //左上角的Y坐标
                int nRightRect, //右下角的X坐标
                int nBottomRect //右下角的Y坐标
            );

            BOOL RoundRect(
               HDC hdc,
               int nLeftRect,
               int nTopRect,
               int nRightRect,
               int nBottomRect,
               int nWidth,
               //指定用来画圆角的椭圆的宽
               int nHeight
               //指定用来画圆角的椭圆的高
            );

    3.6 圆的使用
        Ellipse     - 绘制圆 或 椭圆      

        BOOL Ellipse(
         HDC hdc,
         //绘图设备句柄(BeginPaint函数的返回值)
         int nLeftRect,
         //左上角的X坐标       
         int nTopRect,
         //左上角的Y坐标       
         int nRightRect,
         //右下角的X坐标       
         int nBottomRect
         //右下角的Y坐标
        );


    3.7 圆弧的使用
        //设置圆弧的方向
         int SetArcDirection(
           HDC hdc,    
           //句柄
           int ArcDirection
           //圆弧的方向
           //AD_CLOCKWISE 顺时针
           //AD_COUNTERCLOCKWISE 逆时针
        );          


        BOOL Arc(
            HDC hdc,
            int xLeft,
            int yTop,
            //外接矩形的左上角坐标
            int xRight,
            int yBottom,
            //外接矩形的右下角坐标
            int XStart,
            int YStart,
            //圆弧的起点坐标
            int XEndA,
            int YEnd
            //圆弧的终点坐标
            ); 

Lesson11

4 GDI绘图对象    - 画笔  
    4.1 画笔相关
         作用:线的颜色,线型(实线,虚线),线粗

         HPEN    - 画笔的句柄

    4.2 画笔的使用
        4.2.1  创建画笔  -  CreatePen
            HPEN CreatePen( 
              int fnPenStyle,
              //画笔的样式
              int nWidth, 
              //画笔的宽度
              COLORREF crColor
              //画笔的颜色
            );//创建成功,返回画笔句柄

           PS_SOLID   - 实心先,可以支持1个单位宽度

           其它所有的风格,只能是1个单位的宽度  例如:PS_DASH


       4.2.2 将画笔应用到DC中  - SelectObject  
            HGDIOBJ SelectObject( 
              HDC hdc,   //DC句柄
              HGDIOBJ hgdiobj
              //绘图对象句柄          
            ); //返回旧的绘图对象句柄


       4.2.3 绘图


       4.2.4  取出DC中的画笔    -  SelectObject
              将原来的画笔,使用SelectObject函数放入到DC中,
              就会将我们创建的画笔取出

       4.2.5  释放画笔    -  DeleteObject
               BOOL DeleteObject(
                 HGDIOBJ hObject
                 //绘图对象句柄
               ); 


            只能删除不被DC使用的画笔,所以在释放画笔之前,必须
            将画笔从DC中取出


5 GDI 绘图对象     - 画刷        
      5.1  画刷 
          作用:给封闭图形填充颜色,图案

          HBRSH    - 画刷句柄


      5.2 画刷的使用 
            5.2.1 创建画刷
               CreateSolidBrush          - 创建实心的画刷
               HBRUSH CreateSolidBrush( 
                  COLORREF crColor
                  //画刷的颜色
                ); //创建成功,返回画刷的句柄


               CreateHatchBrush          - 创建阴影画刷
               HBRUSH CreateHatchBrush(
                   int      fnStyle,
                   //阴影样式
                   COLORREF clrref
                   //画刷的颜色
                );//创建成功,返回画刷的句柄


               CreatePatternBrush        - 创建位图画刷   
               HBRUSH CreatePatternBrush( 
                  HBITMAP hbmp
                  //位图句柄
                );//创建成功,返回画刷的句柄

               //加载位图
              HBITMAP LoadBitmap( 
                  HINSTANCE hInstance, 
                    //应用程序实例句柄
                  LPCTSTR lpBitmapName
                    //字符串资源ID
                );//返回位图句柄


            5.2.2 将画刷应用到DC中  
                    - SelectObject  


            5.2.3 绘图


            5.2.4  取出DC中的画刷    
                -  SelectObject


            5.2.5  释放画刷
                -  DeleteObject    

        5.3 其它
          可以使用GetStockObject函数获取系统的画刷,画笔等           

          如果我们不使用画刷填充,需要使用NULL_BRUSH参数,获取不填充的画刷

          GetStockObject返回的画刷不需要释放


 6  GDI绘图对象        - 位图 
      6.1 位图相关
          光栅图形    -  记录每个点的颜色等信息
          矢量图形    -  记录图像的算法,绘图的指令

          HBITMAP      - 位图句柄

     6.2 位图的使用
          6.2.1 添加位图资源

          6.2.2 加载位图资源 

          6.2.3  创建一个与当前DC相匹配的DC
                 HDC CreateCompatibleDC( 
                      HDC hdc 
                      //当前的绘图设备,可以为NULL (使用屏幕DC)
                    ); //返回内存DC句柄

                为什么要弄一个内存DC?
                为了不让用户看见成像的过程,提升用户体验 

          6.2.4 将位图应用内存DC (内存DC得到位图的时候,就将这个位图绘制在虚拟区域中)
                SelectObject


          6.2.5 绘制位图(成像)     

               BOOL BitBlt(         //1:1成像
                   HDC   hdcDest,   //目标DC
                   int   nXDest,    //目标的左上角的x坐标
                   int   nYDest,    //目标的左上角的y坐标
                   int   nWidth,    //目标的宽度    (成像多少图形)
                   int   nHeight,   //目标的高度
                   HDC   hdcSrc,    //源DC
                   int   nXSrc,     //源的左上角的x坐标
                   int   nYSrc,     //源的左上角的y坐标
                   DWORD dwRop      //绘制方法  
                );

               BOOL StretchBlt(     //缩放成像
                  HDC hdcDest,      //目标DC 
                  int nXOriginDest, //目标的左上角的x坐标  
                  int nYOriginDest, //目标的左上角的y坐标
                  int nWidthDest,   //目标的宽度
                  int nHeightDest,  //目标的高度
                  HDC hdcSrc,       //源DC
                  int nXOriginSrc,  //源的左上角的x坐标 
                  int nYOriginSrc,  //源的左上角的y坐标
                  int nWidthSrc,    //源DC宽     (拷贝多少图形)
                  int nHeightSrc,   //源DC高
                  DWORD dwRop       //绘制方法
                );

          6.2.6 取出位图
               SelectObject

          6.2.7 释放位图
              DeleteObject

          6.2.8 释放内存DC
              DeleteDC            


     6.3 其它

        使用GetObject  获取位图信息       
          int GetObject(
            HGDIOBJ hgdiobj,
            //绘图对象的句柄
            int     cbBuffer,
            //缓冲区的大小
           LPVOID  lpvObject
           //缓冲区
        );

        BITMAP 位图信息的结构
        /* Bitmap Header Definition */
            typedef struct tagBITMAP
              {
                LONG        bmType;
                LONG        bmWidth;
                LONG        bmHeight;
                LONG        bmWidthBytes;
                WORD        bmPlanes;
                WORD        bmBitsPixel;
                LPVOID      bmBits;
              } BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP;

Lesson 12

十一、坐标系
1. 坐标系的分类

   1.1 设备坐标系(以显示器为例)

      以像素为单位,设备的左上角为原点,X轴右为正,Y轴下为正的坐标系

      1.1.1 屏幕坐标系
            - 以当前显示器的左上角为原点

      1.1.2 窗口坐标系
            - 以当前窗口的左上角为原点

      1.1.3 窗口客户区坐标系
            - 以当前窗口的客户区左上角为原点


   1.2 逻辑坐标系(计算机的是逻辑坐标系)
        在GDI绘图中,使用的是逻辑坐标绘图


2 坐标的映射关系
   2.1 映射模式
        逻辑坐标和设备坐标之间的映射关系 (1逻辑单位=几个设备单位)

        设备坐标的单位由设备自己决定,大小固定(显示器的像素,打印机1/1440英寸)  


        逻辑坐标的单位可以通过程序设置 

        int SetMapMode(
           HDC hdc, //DC句柄
           int fnMapMode //新的映射模式
        );//返回旧的映射模式


    MM_TEXT                  - 1个逻辑单位 = 1个设备单位(默认默认)(x轴右为正,y轴下为正)   
    MM_HIENGLISH             - 1个逻辑单位 = 0.001英寸(x轴右为正,y轴上为正)     
    MM_LOENGLISH             - 1个逻辑单位 = 0.01英寸 (x轴右为正,y轴上为正)
    MM_HIMETRIC              - 1个逻辑单位 = 0.01毫米 (x轴右为正,y轴上为正) 
    MM_LOMETRIC              - 1个逻辑单位 = 0.1毫米  (x轴右为正,y轴上为正) 
    MM_TWIPS                 - 1个逻辑单位 = 1/1440   (x轴右为正,y轴上为正) (可以用来打印预览)

    逻辑单位转换成具有任意比例的任意单位
    MM_ISOTROPIC             - 1个逻辑单位 = 自定义

    MM_ANISOTROPIC           
                             X轴的1个逻辑单位 = 自定义1
                             Y轴的1个逻辑单位 = 自定义2

    用SetWindowExtEx 和 SetViewportExtEx 函数可指定单位、方向和比例

              BOOL SetWindowExtEx(
                    HDC    hdc,
                    //DC句柄
                    int    nXExtent,        1
                    //x轴的逻辑比例
                    int    nYExtent,        1
                    //y轴的逻辑比例
                    LPSIZE lpSize
                    //原来的比例
                );



            BOOL SetViewportExtEx(
                    HDC    hdc,
                    //DC句柄
                    int    nXExtent,
                    //x轴的设备比例         2
                    int    nYExtent,
                    //y轴的设备比例         3
                    LPSIZE lpSize
                    //原来的比例
                );

十二、文字和字体
1 绘制文字
1.1 TextOut - 将文字绘制到指定的位置
1.2 DrawText - 将文字绘制到矩形区域内

        int DrawText(    
           HDC     hDC,         //DC句柄
           LPCTSTR lpchText,    //字符串BUFF
           int     nCount,      //字符串长度
           LPRECT  lpRect,      //矩形区域BUFF
           UINT    uFormat      //绘制方式
        );


       BOOL ExtTextOut( 
          HDC hdc,               //DC句柄
          int X,                 //字符串的x坐标
          int Y,                 //字符串Y坐标
          UINT fuOptions,        //输出选项(基本不用,给0就可以)
          const RECT* lprc,      //输出矩形区域(基本不用,给NULL)
          LPCTSTR lpString,      //字符串的BUFF
          UINT cbCount,          //字符串的长度
          const int* lpDx        //字符的间距数组
        ); 

      注:字符间距是上一个字符的开始到下一个字符开始之间的距离      


2 文字的颜色和背景  

    文字的颜色的设置
    COLORREF SetTextColor(
        HDC hdc,          
        COLORREF crColor    //要设置的文字的颜色
    );


    文字的背景颜色的设置
    COLORREF SetBkColor(
        HDC hdc,          
        COLORREF crColor    //要设置的文字的颜色
    );//执行成功,返回旧文字的背景颜色


    文字的背景模式
    int SetBkMode(
       HDC hdc,
       int iBkMode //背景模式 OPAQUE/TRANSPARENT 不透明/透明
    );

    注:透明时SetBkColor失效



3 字体 ( GDI绘图对象 )
    3.1 字体相关    
       字体名:  标识字体的类型
       HFONT    - 字体句柄


    3.2 字体的使用
      3.2.1 创建字体 CreateFont
            HFONT CreateFont(
               int     nHeight,            //字体的高度
               int     nWidth,             //字体的宽度
               int     nEscapement,        //字体的切斜度(以度为单位)
               int     nOrientation,       //字体的旋转度(二维编程看不出效果)
               int     fnWeight,           //字体的粗度
               DWORD   fdwItalic,          //是否是斜体(TRUE 是,FALSE否)
               DWORD   fdwUnderline,       //是否有下划线
               DWORD   fdwStrikeOut,       //是否有删除
               DWORD   fdwCharSet,         //字符集(汉语操作系统定死GB2312_CHARSET)
               DWORD   fdwOutputPrecision, //输出精度(基本无效 置0)
               DWORD   fdwClipPrecision,   //裁剪精度(基本无效 置0)
               DWORD   fdwQuality,         //输出质量(基本无效 置0)
               DWORD   fdwPitchAndFamily,  //匹配字体(基本无效 置0)
               LPCTSTR lpszFace            //字体名称
            );//返回创建的字体的句柄


    3.2.2 将字符应用到DC中
          SelectObject

    3.2.3 绘制文字

    3.2.4 从DC中取出字体
           SelectObject 

    3.2.5 释放字体
          DeleteObject

十三 对话框
1 对话框的分类
1.1 模式(态)对话框 - 当对话框显示时,会禁止本进程的其它窗口和用户
进行交互操作

      1.2  非模式(态)对话框      -  当对话框显示时,其它窗口同样可以和用户进行交互操作 


      模式对话框和非模式对话框的创建和销毁完成不同



  2 对话框的基本使用
    2.1   对话框的窗口处理函数


    2.2   创建对话框

    2.3   对话框的关闭


  3 模式对话框的使用
       3.1 对话框的处理函数 DialogProc (并非真正的对话框处理函数)     

          BOOL CALLBACK DigLogProc(
            HWND hwndDlg,    //对话框的窗口句柄
            UINT uMsg,       //消息ID
            WPARAM wParam,   //消息附带参数1
            LPARAM lParam    //消息附带参数2
          );

         对话框的处理函数的调用和普通的窗口不同

         普通的窗口处理函数是自定义调用缺省
          WindowProc(.......)
          {

                return DefWindowProc(.....);
          }           


          对话框处理函数是缺省调用自定义
          SysDlgProc(...)
          {
              ....;                   //区分是哪个对话框的消息,
                                      //并调用相应的自定义的处理函数

              if ( DialogProc )
                return;

             ......;                   //缺省的各种消息的默认处理
          }


          返回FALSE    - 表示DialogProc没有处理这个消息
                         交给缺省处理函数去处理

          返回TRUE     - 表示DialogProc处理了这个消息
                         直接返回,缺省的处理函数不处理


        3.2 创建模式对话框
           int DialogBox( 
              HINSTANCE hInstance,   //应用程序实例句柄
              LPCTSTR lpTemplate,    //对话框字符串资源ID
              HWND hWndParent,       //父窗口句柄
              DLGPROC lpDialogFunc   //自定义的对话框处理函数
            ); 

            需要添加对话框资源;
            DialogBox是一个阻塞函数,只有当对话框关闭后才会返回,
            继续执行后续代码;
            返回值由EndDialog指定

        3.3 模式对话框的关闭    
            BOOL EndDialog(  //销毁对话框同时让DialogBox返回
              HWND hDlg,     //对话框句柄
              int nResult    //指定DialogBox函数的返回值
            ); 

            注:关闭模式对话框只能用EndDialog函数,不能使用DestroyWindow函数。
                DestroyWindow虽然能销毁窗口,但是不能让DialogBox返回

        3.4 对话框的消息
             对话框没有WM_CREATE消息,取而代之的是 WM_INITDIALOG

             WM_INITDIALOG  - 对话框创建成功,但还未显示之前产生,
                              可以完成自己的初始化工作       

    4. 非模式对话框
         4.1 对话框的处理函数(与模式对话框处理函数一样)


         4.2 创建非模式对话框           

            HWND CreateDialog( 
              HINSTANCE hInstance,  //应程序实例句柄
              LPCTSTR lpTemplate,   //对话框字符串资源ID
              HWND hWndParent,      //父窗口
              DLGPROC lpDialogFunc  //窗口处理函数
            );  

           非阻塞函数,创建成功返回对话框窗口句柄,
           需要使用ShowWindow函数显示对话框


        4.3 非模式对话框的关闭
             关闭时使用DestroyWindow销毁窗口,不要使用EndDialog关闭非模式对话框


    5 对话框VS普通窗口
       5.1 创建
            模式对话框       - DialogBox,阻塞函数        
            无模式对话框     - CreateDialog
            普通窗口         - CreateWindow/CreateWindowEx

       5.2 窗口处理函数
           对话框            - DialogProc(并非真正的对话框处理函数) 
           普通窗口          - WindowProc,需要调用缺省窗口处理函数 

       5.3 窗口消息
            普通窗口         - WM_CREATE
            对话框           - WM_INITDIALOG

       5.4 窗口关闭
             模式对话框               - EndDialog
             无模式对话框/普通窗口    -DestroyWindow 

Lesson13

十四、子控件
1. 子控件相关
系统已经定义(注册)的窗口类型,相应的处理函数都已经有系统完成。
例如:按钮,文件编辑框等等

 2. 子控件的创建
     不需要注册,直接使用CreateWindow/CreateWindowEx函数创建该类的窗口。
     子控件创建时,每个控件都有唯一的ID。


 3. 控件的消息
      程序和控件的交互,通过消息完成

      3.1 控件的窗口消息
           程序员可以使用SendMessage函数,向控件发送消息,
           获取控件的信息和设置控件的状态             

      3.2  控件的通知消息
            控件有相应的事件发生后,会向父窗口发送通知消息(WM_COMMAND),
            父窗口根据控件ID,做相应的处理

十五、静态框
1. 静态框的分类
文字静态框 - 显示文字
图标静态框 - 显示图标 设置SS_ICON/SS_BITMAP

   2.静态框作用
     作用:显示文字或图像,类名"STATIC"  

   3.静态框的使用
      3.1 创建
         3.1.1 函数CreateWindow/CreateWindowEx函数

         3.1.2 风格
             图标静态框使用SS_ICON/SS_BITMAP风格
             如果要创建图标静态框,那么窗口名称参数要设置为图标或者位图的ID                            


            例如:
              CreateWindowEx(0,"STATIC","#101",.....);              

      3.2 静态框控件的窗口消息
           SendMessage函数发送到控件(处理函数)即可

            例如:STM_SETICON
                    WPARAM     - 图标句柄
                    LPARAM     - 未使用,必须为0                       



      3.3 控件的通知消息(通知码:STN_CLICKED)

           需要在创建控件时增加SS_NOTIFY风格

           通知消息通过 WM_COMMAND 消息发送到父窗口

         附: 
            WM_COMMAND
              WPARAM 
                 LOWORD        -菜单、快捷键、控件的ID
                 HIWORD        -对于菜单     0
                               -对于快键键    1
                               -对于控件  通知码(Notificaton Code)                                    

              LPARAM           -对于菜单、快捷键为NULL
                               -对于控件为控件句柄                  

Lesson14

十六、按钮(Button)
根据按钮的风格,将按钮分为4类
1. 按钮相关 <

声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
  • 上一篇:没有了
  • 下一篇:没有了
未上传头像