快捷搜索:

您的位置:澳门新葡4473网站 > 新葡亰平台娱乐 > Windows程序设计零基础自学_2_Windows程序的显示和更

Windows程序设计零基础自学_2_Windows程序的显示和更

发布时间:2019-10-11 03:51编辑:新葡亰平台娱乐浏览(183)

    CHECKER1程序将客户区划分成25个矩形,构成一个5*5的数组。如果在其中一个矩形内单击鼠标,就用X形填充该矩形。再次单击,则X形消失。

         前面的一篇文章里面,我模仿那本经典的书写了一个windows程序, 对windows的程序设计有了一点点的感性认识, 但是对于程序的设计还是一知半解,因此需要继续自学, 接着看那本经典的书......

    图片 1图片 2

         下面是我的一点总结吧,贴出来让各位大侠看看,希望大侠们不吝指教, 指出我认识中的不当之处,以帮助我在自学的过程中提高.......

      1 /*--------------------------------------------
      2 CHECKER1.C -- Mouse Hit-Test Demo Program No.1
      3               (c) Charles Petzold, 1998
      4 --------------------------------------------*/
      5 
      6 #include <Windows.h>
      7 
      8 #define DIVISION 5
      9 
     10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
     11 
     12 int WINAPI WinMain( __in HINSTANCE hInstance
     13                     , __in_opt HINSTANCE hPrevInstance
     14                     , __in LPSTR lpCmdLine
     15                     , __in int nShowCmd )
     16 {
     17     static TCHAR szAppName[] = TEXT("Checker1");
     18     HWND hwnd;
     19     MSG msg;
     20     WNDCLASS wndclass;
     21 
     22     wndclass.style = CS_HREDRAW | CS_VREDRAW;
     23     wndclass.lpfnWndProc = WndProc;
     24     wndclass.cbClsExtra = 0;
     25     wndclass.cbWndExtra = 0;
     26     wndclass.hInstance = hInstance;
     27     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     28     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
     29     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
     30     wndclass.lpszMenuName = NULL;
     31     wndclass.lpszClassName = szAppName;
     32 
     33     if (!RegisterClass(&wndclass))
     34     {
     35         MessageBox(NULL, TEXT("Program requires Windows NT!")
     36             , szAppName, MB_ICONERROR);
     37         return 0;
     38     }
     39 
     40     hwnd = CreateWindow(szAppName, TEXT("Checker1 Mouse Hit-Test Demo")
     41         , WS_OVERLAPPEDWINDOW
     42         , CW_USEDEFAULT, CW_USEDEFAULT
     43         , CW_USEDEFAULT, CW_USEDEFAULT
     44         , NULL, NULL, hInstance, NULL);
     45 
     46     ShowWindow(hwnd, nShowCmd);
     47     UpdateWindow(hwnd);
     48 
     49     while (GetMessage(&msg, NULL, 0, 0))
     50     {
     51         TranslateMessage(&msg);
     52         DispatchMessage(&msg);
     53     }
     54 
     55     return msg.wParam;
     56 }
     57 
     58 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     59 {
     60     static BOOL fState[DIVISION][DIVISION];
     61     static int cxBlock, cyBlock;
     62     HDC hdc;
     63     int x, y;
     64     PAINTSTRUCT ps;
     65     RECT rect;
     66 
     67     switch (message)
     68     {
     69     case WM_SIZE:
     70         cxBlock = LOWORD(lParam) / DIVISION;
     71         cyBlock = HIWORD(lParam) / DIVISION;
     72         return 0;
     73 
     74     case WM_LBUTTONDOWN:
     75         x = LOWORD(lParam) / cxBlock;
     76         y = HIWORD(lParam) / cyBlock;
     77 
     78         if (x < DIVISION && y < DIVISION)
     79         {
     80             fState[x][y] ^= 1;
     81 
     82             rect.left = x * cxBlock;
     83             rect.top = y * cyBlock;
     84             rect.right = (x + 1) * cxBlock;
     85             rect.bottom = (y + 1) * cyBlock;
     86 
     87             InvalidateRect(hwnd, &rect, FALSE);
     88         }
     89         else
     90             MessageBeep(0);
     91         return 0;
     92 
     93     case WM_PAINT:
     94         hdc = BeginPaint(hwnd, &ps);
     95 
     96         for (x = 0; x < DIVISION; ++x)
     97             for (y = 0; y < DIVISION; ++y)
     98             {
     99                 Rectangle(hdc, x * cxBlock, y * cyBlock
    100                     , (x + 1) * cxBlock, (y + 1) * cyBlock);
    101 
    102                 if (fState[x][y])
    103                 {
    104                     MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL);
    105                     LineTo(hdc, (x + 1) * cxBlock, (y + 1) * cyBlock);
    106                     MoveToEx(hdc, x * cxBlock, (y + 1) * cyBlock, NULL);
    107                     LineTo(hdc, (x + 1) * cxBlock, y * cyBlock);
    108                 }
    109             }
    110 
    111         EndPaint(hwnd, &ps);
    112         return 0;
    113 
    114     case WM_DESTROY:
    115         PostQuitMessage(0);
    116         return 0;
    117     }
    118 
    119     return DefWindowProc(hwnd, message, wParam, lParam);
    120 }
    

         哈哈哈..........

    CHECKER1.C

    4.1   显示和更新
    windows应用程序的显示区域:
           除标题栏、应用程序边框、菜单栏、工具栏、滚动条和状态条外的系统分配给应用程序的窗口区域。
    Windows显示文字和图形的方式:
           1、通过绘制应用程序的显示区域来实现
           2、当应用程序的某些部分被覆盖后,windows不会保存被覆盖的区域,当程序移开后,windows通过发送消息通知
                应用程序需要重新绘制被覆盖的区域来实现显示
           3、windows通过发送WM_PAINT消息来通知应用程序的窗口消息处理程序,需要重新绘制显示区域
    4.2  WM_PAINT消息:
      WM_PAINT消息的产生时机:
           1、在调用UpdateWindow函数时,windows会像应用程序发送一个WM_PAINT消息,通知应用程序需要重绘显示区域。
           2、在应用程序的使用者移动窗口时,窗口中先前被隐藏的区域重新可见
           3、使用者改变窗口的大小,同时wndclass.style 中设定了CS_VREDRAW 和CS_HREDRAW
           4、程序中调用ScrollWindow或ScrollDC函数滚动显示区域的一部分
           5、程序中使用InvalidateRect或InvalidateRgn函数产生WM_PAINT消息

    CHECKER1程序显示结果如图所示:

     可能产生WM_PAINT的时机:
           1、Windows擦除了覆盖应用程序的对话框或者消息框
           2、菜单下拉下拉后然后被释放
           3、显示ToolTip提示信息后
       以下情况Windows通过保存信息来恢复显示区域
           1、鼠标的光标穿越显示区域
           2、图标拖过显示区域
       处理过程:
          应用程序保留重新绘制显示区域的所有信息,并且当接收到WM_PAINT消息时进行显示区域的重新绘制或者第一绘制(UpdateWindow时)
    4.3 无效矩形和有效矩形
       无效矩形:
           1、应用程序的显示区域中被覆盖的区域就是无效矩形区域。无效矩形也称作无效区域。
           2、正是因为无效矩形的存在才使Windows发送WM_PAINT消息给应用程序,只有在显示区域的某一部分失效后应用程序窗口才会接收WM_PAINT消息
       绘图信息结构:
           1、 windows内部为每一个窗口保存一个绘图信息结构, 这个结构包含了包围无效区域的最小矩形的坐标以及其他信息
           2、如果在应用程序处理WM_PAINT消息之前, 显示区域的另一个区域变为无效,则windows会计算出一个包含两个区域的新的无效区域,并将这种变化信息保存在绘图信息结构
           3、windows不会将多个WM_PAINT消息放到消息对列
       InvalideateRect函数
           1、窗口消息处理程序可以通过呼叫InvalidateRectangular使显示区域内的矩形无效
           2、调用InvalidateRect函数时如果消息队列中已经存在WM_PAINT,即已经存在无效区域,windows将计算新的无效区域。如果消息队列无WM_PAINT则将
              一个WM_PAINT消息投递到消息队列。
           3、在接收到WM_PAINT消息时,窗口处理程序/函数可以取得无效区域的坐标。
           4、在任何时刻可以通过呼叫GetUpdateRect取得无效区域的坐标
       Tip:
           在处理WM_PAINT消息时,窗口消息处理程序在呼叫BeginPaint之后整个区域立即变为有效, 程序也可以通过呼叫ValidateRect函数使显示区域内的任意矩形都变为有效。
           如果呼叫具有令整个显示区域变为有效的效果,则当前消息队列中的WM_PAINT都将被删除。
    4、4 GDI
       GDI:
            要在窗口显示区域绘图,可以使用windows的图像设备接口:GDI
       文字绘制:
            1、DrawText函数
            2、TextOut函数
               原型: TextOut(HDC hdc, int x, int y,char *psText,int iLength);
               hdc: 设备内容句柄
               x:显示文字开始的x坐标
               y: 显示文字开始的y坐标
               psText: 指向要显示的字符串的指针
               iLength: 待显示字符串的长度
       设备内容:
           1、设备内容句柄是GDI函数的通行证,通过设备内容句柄, 程序就可以在显示区域上绘图。
           2、设备内容 DC: 是GDI内部保存的数据结构,设备内容与特定的显示设备相关。对于系统桌面, 设备内容总是与显示器上的特定窗口相关
           3、设备内容中有些值是图形属性,这些属性定义了GDI绘图函数的细节。
       通过设备内容绘图的过程:
           1、程序需要绘图时,必须取得设备内容句柄,在取得该句柄后,windows系统用内定的属性值填入内部设备内容结构
           2、可以呼叫不同的GDI函数获取设备内容的属性值
           3、可以呼叫GDI函数改变设备内容的属性值
           4、利用其他GDI函数在显示区域绘图
           5、当程序在显示区域绘图完毕后,必须释放设备内容句柄, 被释放的句柄不能再被使用
           6、程序必须在处理单个消息处理期间取得和释放设备内容句柄。
           Tip:
             除了呼叫CreateDC建立的设备内容外,程序不能在两个消息之间保存其他设备内容句柄。
       获取设备内容句柄:  
       方法一:处理WM_PAINT消息时使用
           1、BeginPaint和EndPaint函数
                BeginPaint和EndPaint函数需要窗口句柄(在windows呼叫应用程序窗口处理函数时,作为参数传递给应用程序窗口处理函数)
              和PAINTSTRUCT结构的地址作为参数。
                BeginPaint函数返回一个与窗口相关联的设备内容句柄。
               其原型如下:
                            HDC  BeginPaint(HWND, PAINTSTRUCT *)
               而EndPaint函数释放由BeginPaint函数取得的设备内容句柄,其原型如下:
                                 EndPaint(HWND, PAINTSTURCT *)
           2、WM_PAINT消息处理过程
              PreStep:
                      HDC hdc;
                      PAINTSTRUCT  ps;
              step1: 首先呼叫BeginPaint函数取得一个与窗口相关联的设备内容句柄;
                      hdc=BeginPaint(hwnd,&ps);
              Step2:  使用GDI函数进行绘图;
              Step3: 释放由BeginPaint函数取得设备内容句柄:
                      EndPaint(hwnd,&ps);
              EndStep: return 0;//在每一个消息处理完后,均需要返回到windows系统,并且如果成功执行窗口回调函数则返回0.
           3、WM_PAINT消息处理结构:
                case WM_PAINT:
                         hdc=BeginPaint(hwnd,&ps);
                         call other GDI function
                         EndPaint(hwnd,&ps);
                         return 0;
           4、 如果在窗口消息处理函数中不处理WM_PAINT消息,则必须将WM_PAINT消息传递给DefWindowProc函数进行处理,DefWindowProc函
               数以下面的代码处理WM_PAINT消息:
                case WM_PAINT:
                     BeginPaint(hwnd,&ps);
                     EndPaint(hwnd,&ps);
                     return 0;
               说明以下DefWindowProc的原型:
                      DefWindowProc(HWND, MSG,WPARAM,LPARAM);//与窗口消息处理函数基本一样的结构
           5、windows产生WM_PAINT消息是因为显示区域的某个区间变为无效, 如果不呼叫BeginPaint和EndPaint,或者ValidateRect,则windows
             不会是无效区域变为有效,相反windows会发送另一个WM_PAINT消息,且一直发送过去。 
       绘图信息结构  PAINTSTRUCT:
           1、绘图信息结构定义:
                  typedef struct tagPAINTSTRUCT
                    {
                         HDC   hdc;   //设备内容句柄
                         BOOL  fErase;  //是否已经擦除无效矩形的背景
                         RECT  rcPaint;
                         BOOL  fRestore;
                         BOOL  fIncUpdate;
                         BYTE  rgbReserved[32];
                     }PAINTSTRUCT;
            2、windows 呼叫
                  在程序呼叫BeginPaint函数时,windows会将该结构的各个成员填充好,应用程序只使用前三个字段,其他由windows内部使用。
               呼叫BeginPaint函数时填充ps.fErase字段来表示是否已经擦除无效区域的背景:
                      ps.fErase = FALSE (0) 则表示已经擦除无效区域背景;同时windows会使用wndclass.hbrBcakground指定的画刷来擦除背景。

    图片 3

            3、如果程序呼叫InvalidateRect使显示区域中的矩形失效,则InvalidateRect函数的最后一个参数会指定是否擦除背景。如果这个参数为FALSE
               则windows不会擦除背景,并且在呼叫完BeginPaint后将置 ps.fErase=TRUE 非零。
               在处理WM_PAINT消息时,如果需要在无效区域外进行重绘,可以呼叫InvalidateRect函数:
                Exp:
                     InvalidateRect(hwnd,NULL,TRUE);
                在BeginPaint函数之前呼叫InvalidateRect函数使整个显示区域变为无效,并擦除背景;但如果最后一个参数等于FALSE,则不会擦除背景,窗口
                中原有的信息还保留在原处。
            4、RECT rcPaint 是一个RECT型的结构体, PAINTSTRUCT结构中的rcPaint成员定义了无效区域的边界。

    所有25个矩形具有相同的宽度和高度,这些宽度和高度被保存在cxBlock、cyBlock中。无论何时改变客户区的大小,程序都将重新计算cxBlock、cyBlock。WM_LBUTTONDOWN处理逻辑利用鼠标的坐标来判断哪个矩形被单击,然后在fState数组中使用位运算符(按位异或^)计算那个矩形的新状态,最后强制使该矩形失效,从而产生WM_PAINT消息。

    前面的内容简单的描述了利用BeginPaint和EndPaint函数来处理WM_PAINT消息的机制,理解不到位的地方请各位见谅。

    如果客户区的宽度和高度不能被5整除,客户区的左边或底部就会出现一个小长条区域,不被举行覆盖。在这片区域进行鼠标单击时,CHECKER1程序会调用MessageBeep函数进行响应。

        上面的一些函数的原型没有指明返回值类型, 大家可以通过编译环境自己查看, 因为我有点懒,所以就没查看了。

    当CHECKER1程序收到WM_PAINT消息时,它会重新绘制整个客户区,利用GDI中的Rectangle函数画出所有的矩形。若fState值为真,则CHECKER1程序调用函数MoveToEx和函数LineTo函数画出两条直线。

        哈哈哈哈................原来windows下的程序设计有C的基础,加上学习一大堆windows定义各种API函数, 加上一些运行机制的理解,就算是菜鸟级的不入门的程序编程人员(就像我似的)也能实现一个简单的应用....................

        我发现用LiveWrite这个东西比较好.......

    本文由澳门新葡4473网站发布于新葡亰平台娱乐,转载请注明出处:Windows程序设计零基础自学_2_Windows程序的显示和更

    关键词:

上一篇:第七章 鼠标(CHECKER3)

下一篇:没有了