zwz_good  

program Sysmets3;

uses
  windows,
  Messages, Math,
  sysmets in '..\sysmets.pas';

function WndProc(hwindow: HWND; message: UINT; wParam, lParam: LongInt): LRESULT; stdcall;
{$J+}
const
  cxChar: Integer = 0;
  cyChar: Integer = 0;
  cxCaps: Integer = 0;
  cyClient: Integer = 0;
  iVscrollPos: Integer = 0;
{$J-}
var
  i: Integer;
  tmpHdc: HDC;
  tm: TTextMetric;
  si: TScrollInfo;
  ps: TPaintStruct;
  hdc1: HDC;
  iVscrollOldPos: integer;
  szBuff: array[0..5] of AnsiChar;
  OutList: Integer;
  iBegin, iEnd: integer;
begin
  Result:= 0;
  case message of
  WM_CREATE:
  begin
    tmpHdc:= GetDC(hwindow);
    GetTextMetrics(tmpHdc, tm);
    ReleaseDC(hwindow, tmpHdc);
    cyChar:= tm.tmHeight + tm.tmExternalLeading;
    cxChar:= tm.tmAveCharWidth;
    if (tm.tmPitchAndFamily and $1 = 0) then
      cxCaps:= cxChar
    else
      cxCaps:= (cxChar*3) div 2;
  end;
  WM_DESTROY:
  begin
    PostQuitMessage(0);
  end;
  WM_SIZE:
  begin
    cyClient:= HiWord(lParam);
    si.cbSize:= SizeOf(si);
    si.fMask:= SIF_RANGE or SIF_PAGE or SIF_POS;//SIF_ALL;
    si.nMin:= 0;
    si.nMax:= NUMLINES-1;
    si.nPage:= cyClient div cyChar;
    si.nPos:= 0;
    //si.nTrackPos
    SetScrollInfo(hwindow, SB_VERT, si, True);
  end;

  WM_VSCROLL:
  begin
    si.cbSize:= SizeOf(si);
    si.fMask:= SIF_POS;
    GetScrollInfo(hwindow, SB_VERT, si);
    iVscrollOldPos:= si.nPos;
    case LOWORD(wParam) of
    SB_LINEUP:
    begin
      Dec(iVscrollPos);
    end;
    SB_LINEDOWN:
    begin
      Inc(iVscrollPos);
    end;
    SB_PAGEUP:
    begin
      Dec(iVscrollPos, cyClient div cyChar);
    end;
    SB_PAGEDOWN:
    begin
      Inc(iVscrollPos, cyClient div cyChar);
    end;
    SB_THUMBTRACK:
    begin
      iVscrollPos:= HiWord(wParam);
    end;
    end;
    si.cbSize:= SizeOf(si);
    si.fMask:= SIF_POS;
    si.nPos:= iVscrollPos;
    SetScrollInfo(hwindow, SB_VERT, si, True);
    GetScrollInfo(hwindow, SB_VERT, si);
    if (iVscrollOldPos <> si.nPos) then
    begin      //重绘窗口

      //此句通知系统本窗口需要垂直滚动cyChar*(iVscrollOldPos-si.nPos)距离
      //为此该窗口可能会产生无效区域,所以要在WM_PAINT消息中重点处理无效区域
      //比如滚动条向下滚动时,即会出现整个窗口内容向上滚动,因此向上部分由于
      //客户区的限制被自然裁剪掉了,
      //可是窗口下部分会出现问题,此时这个部分(区域)称为无效区域,要在重绘消息中处理。

      ScrollWindow(hwindow, 0, cyChar*(iVscrollOldPos-si.nPos), nil, nil);
      UpdateWindow(hwindow); //为了保证拖动滚动条时内容区同时滚动。
    end;
  end;

  WM_PAINT:
  begin
    hdc1:= BeginPaint(hwindow, ps);
    si.cbSize:= SizeOf(si);
    si.fMask:= SIF_POS;
    GetScrollInfo(hwindow, SB_VERT, si);
    iVscrollPos:= si.nPos;
    //仅绘制无效区域
    //(ps.rcPaint.Top div cyChar) 当前从顶端到无效区域的行数
    //si.nPos 当前顶端显示的是Sysmetrics[si.nPos],即第一行在-cyChar*(si.nPos-1)位置处
    //无效区域的第一行在Sysmetrics[]中的索引为
    // (si.nPos-1)+(ps.rcPaint.Top div cyChar)
    //为了确保最小数值在滚动条范围内
    iBegin:= Max(0, iVscrollPos+(ps.rcPaint.Top div cyChar));
    iEnd:= Min(NUMLINES-1, iVscrollPos+(ps.rcPaint.Bottom div cyChar));

    for i := iBegin to iEnd do
    begin

      //i-iVscrollPos 表明原本应该显示在第i行的文字,由于滚动,导致向上显示在地i- iVscrollPos行位置上
      //当滚动条在顶端时,第一行是0,因此第i行就显示在第i行的位置了。

      TextOutA(hdc1, 0, cyChar*(i-iVscrollPos), Sysmetrics[i].szLabel, lstrlenA(Sysmetrics[i].szLabel));
      TextOutA(hdc1, 22*cxCaps, cyChar*(i-iVscrollPos), Sysmetrics[i].szDesc, lstrlenA(Sysmetrics[i].szDesc));
      SetTextAlign(hdc1, TA_RIGHT or TA_TOP);
      OutList:= GetSystemMetrics(Sysmetrics[i].Index);
      ZeroMemory(@szBuff[0], 6);
      TextOutA(hdc1, 22*cxCaps + 44*cxChar, cyChar*(i-iVscrollPos),
         szBuff, wvsprintfA(@szBuff[0],'%5d', @OutList));
      SetTextAlign(hdc1, TA_LEFT or TA_TOP);
    end;

    EndPaint(hwindow, ps);
  end
  else
  begin
    Result:= DefWindowProc(hwindow, message, wParam, lParam);
  end;
  end;
end;
const
  szAppName = 'Sysmets3';
var
  hwindow: HWND;
  wndclass1: TWndClass;
  msg1: TMsg;
begin
  wndclass1.style:= CS_VREDRAW or CS_HREDRAW;
  wndclass1.lpfnWndProc:= @WndProc;
  wndclass1.cbClsExtra:= 0;
  wndclass1.cbWndExtra:= 0;
  wndclass1.hInstance:= HInstance;
  wndclass1.hIcon:= LoadIcon(0, IDI_APPLICATION);
  wndclass1.hCursor:= LoadCursor(0, IDC_ARROW);
  wndclass1.hbrBackground:= GetStockObject(WHITE_BRUSH);
  wndclass1.lpszMenuName:= nil;
  wndclass1.lpszClassName:= szAppName;

  if (RegisterClass(wndclass1) = 0) then
  begin
    MessageBox(0, '本程序需要运行在 windows NT !', szAppName, MB_ICONERROR);
    Exit;
  end;

  hwindow:= CreateWindow(szAppName, 'SysMets No.3', WS_OVERLAPPEDWINDOW or WS_VSCROLL,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, HInstance, nil);

  ShowWindow(hwindow, CmdShow);
  UpdateWindow(hwindow);

  while GetMessage(msg1, 0, 0, 0) do
  begin
    TranslateMessage(msg1);
    DispatchMessage(msg1);
  end;

end.
{
BOOL ScrollWindow(
    HWND hWnd,
    int XAmount,
    int YAmount,
    const RECT *lpRect,
    const RECT *lpClipRect
);
参数 类型及说明
hWnd Long,待滚动窗口的句柄
XAmount Long,水平滚动的距离。正值向右滚动,负值向左滚动
YAmount Long,垂直滚动的距离。正值向下滚动,负值向上滚动
lpRect RECT,用客户区坐标表示的一个矩形,它定义了客户区要滚动的一个部分。如设为NULL,则滚动整个客户区。在NULL的情况下,子窗口和控件的位置也会随同任何无效区域移动。否则,子窗口和无效区域不会一起移动。因此,在滚动之前,如指定了lpRect,一个明智的做法是先调用UpdateWindow函数
lpClipRect RECT,指定剪切区域。只有这个矩形的区域才可能滚动。该矩形优先于lpRect。可设为NULL
  参数:
  hWnd:客户区域将被滚动的窗体句柄。
  XAmount:指定水平滚动以设备为单位的数量。如果窗体被滚动模式为CS_OWNDC或CS_CLASSDC,此参数则使用逻辑单位而不使用设备单位。当向左滚动窗体内容时,参数值必须为负。
  YAmount:指定垂直滚动设备单位数量。如果窗体被滚动模式为CS_OWNDC或CS_CLASSDC,此参数则使用逻辑单位而不使用设备单位。当向上滚动窗体内容时,参数值必须为负。
  lpRect:指向所指定将被滚动的客户区域部分的RECT结构。若此参数为NULL,则整个客户区域均被滚动。
  lpClipRect:指向包含类似于剪辑滚动条RECT结构。只有剪辑矩形条内部的位受影响。由外向内的滚动矩形内部被着色,而由矩形内向外的滚动将不被着色。
}

posted on 2009-04-20 19:34  zwz_good  阅读(234)  评论(0编辑  收藏  举报