windows程序设计读书笔记3——字符显示2

由于显示的字符可能会不全,我们很容易想到的一个解决办法是使用滚动条。

先看一下代码,再进行分析:

/*----------------------------------------------------

   SYSMETS2.C -- System Metrics Display Program No. 2

                 (c) Charles Petzold, 1998

  ----------------------------------------------------*/



#define WINVER 0x0500

#include <windows.h>

#include "sysmets.h"

 

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



int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

     static TCHAR szAppName[] = TEXT ("SysMets2") ;

     HWND         hwnd ;

     MSG          msg ;

     WNDCLASS     wndclass ;



     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

     wndclass.lpfnWndProc   = WndProc ;

     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 = szAppName ;



     if (!RegisterClass (&wndclass))

     {

          MessageBox (NULL, TEXT ("This program requires Windows NT!"), 

                      szAppName, MB_ICONERROR) ;

          return 0 ;

     }



     hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 2"),

                          WS_OVERLAPPEDWINDOW | WS_VSCROLL ,

                          CW_USEDEFAULT, CW_USEDEFAULT,

                          CW_USEDEFAULT, CW_USEDEFAULT,

                          NULL, NULL, hInstance, NULL) ;



     ShowWindow (hwnd, iCmdShow) ;

     UpdateWindow (hwnd) ;



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

     {

          TranslateMessage (&msg) ;

          DispatchMessage (&msg) ;

     }

     return msg.wParam ;

}



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

{

     static int  cxChar, cxCaps, cyChar, cyClient, iVscrollPos ;

     HDC         hdc ;

     int         i, y ;

     PAINTSTRUCT ps ;

     TCHAR       szBuffer[10] ;

     TEXTMETRIC  tm ;



     switch (message)

     {

     case WM_CREATE:

          hdc = GetDC (hwnd) ;



          GetTextMetrics (hdc, &tm) ;

          cxChar = tm.tmAveCharWidth ;

          cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;

          cyChar = tm.tmHeight + tm.tmExternalLeading ;



          ReleaseDC (hwnd, hdc) ;



          SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE) ;

          SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE) ;

          return 0 ;



     case WM_SIZE:

          cyClient = HIWORD (lParam) ;

          return 0 ;



     case WM_VSCROLL:

          switch (LOWORD (wParam))

          {

          case SB_LINEUP:

               iVscrollPos -= 1 ;

               break ;

     

          case SB_LINEDOWN:

               iVscrollPos += 1 ;

               break ;

     

          case SB_PAGEUP:

               iVscrollPos -= cyClient / cyChar ;

               break ;

     

          case SB_PAGEDOWN:

               iVscrollPos += cyClient / cyChar ;

               break ;

     

          case SB_THUMBPOSITION:

               iVscrollPos = HIWORD (wParam) ;

               break ;

     

          default :

               break ;

          }



          iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;



          if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))

          {

               SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;

               InvalidateRect (hwnd, NULL, TRUE) ;

          }

          return 0 ;



     case WM_PAINT:

          hdc = BeginPaint (hwnd, &ps) ;

     

          for (i = 0 ; i < NUMLINES ; i++)

          {

               y = cyChar * (i - iVscrollPos) ;

     

               TextOut (hdc, 0, y,

                        sysmetrics[i].szLabel,

                        lstrlen (sysmetrics[i].szLabel)) ;

     

               TextOut (hdc, 22 * cxCaps, y,

                        sysmetrics[i].szDesc,

                        lstrlen (sysmetrics[i].szDesc)) ;

     

               SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;

     

               TextOut (hdc, 22 * cxCaps + 40 * cxChar, y, szBuffer,

                        wsprintf (szBuffer, TEXT ("%5d"),

                             GetSystemMetrics (sysmetrics[i].iIndex))) ;

     

               SetTextAlign (hdc, TA_LEFT | TA_TOP) ;

          }

          EndPaint (hwnd, &ps) ;

          return 0 ;



     case WM_DESTROY:

          PostQuitMessage (0) ;

          return 0 ;

     }

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

}

我们在CreateWindow函数的第三个参数加上 WS_VSCROLL 即垂直滚动条。

同时在WM_CREATE中加入:

SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE) ;

SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE) ;

SetScrollRange设置滚动条范围,NUMLINES是在头文件中定义的行数,

滚动条的每个位置对应一行文字。

iVscrollPos变量记录这滑块的当前位置。

在鼠标拖动滑块时,会产生WM_VSCROLL消息,对iVscrollPos变量进行赋值操作。

还有更改的一处是Y坐标: y = cyChar * (i - iVscrollPos) ; 这保证了滑动之后,小于当前位置的字符不会输出到屏幕(因为他们Y坐标是负的)

同时在滑动滚动条的时候:

if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))

          {

               SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;

               InvalidateRect (hwnd, NULL, TRUE) ;

          }

当滚动条位置改变之后我们会用InvalidateRect函数使窗口无效,会生成WM_PAINT消息,重绘窗口。

你可能感兴趣的:(windows)