精华内容
下载资源
问答
  • VB6 FORM窗体上控件实现滚动的方法

    万次阅读 2014-09-09 13:54:06
    当所包含的图形超过控件范围时,单独一个 PictureBox 控件无法实现滚动功能─ 因为 PictureBox 控件不能自动添加滚动条。 应用程序使用两个图片框。称第一个为平稳父 PictureBox 控件。称第二个为子 PictureBox

    你将所有的控件都放在窗体的 picturebox控件上


    除了 PictureBox 控件之外,也可用水平、垂直滚动条创建可滚动的图形视口应用程序。当所包含的图形超过控件范围时,单独一个 PictureBox 控件无法实现滚动功能─ 因为 PictureBox 控件不能自动添加滚动条。

    应用程序使用两个图片框。称第一个为平稳的父 PictureBox 控件。称第二个为子 PictureBox 控件,它包含在父图片框中。子图片框中包含图形图象,可用滚动条控件在父图片框中移动子图片框。

    图 7.25   在设计时添加滚动条控件

     

    如图 7.28 所示,先创建一个新工程,然后在窗体上绘制两个图片框、一个水平滚动条和一个垂直滚动条。

    这里,用窗体的 Form_Load 事件设置比例模型,在父图片框中调整子图片框的大小,水平、垂直滚动条将定位并调整它们的大小,然后加载位图图形。将下列代码添加到窗体的 Form_Load 事件过程中:

    Private Sub Form_Load()

       '设置 ScaleMode 为像素。
       Form1.ScaleMode = vbPixels
       Picture1.ScaleMode = vbPixels

       '将 Autosize 设置为 True,以使 Picture2 的边界
       '扩展到实际的位图大小。
       Picture2.AutoSize = True

       '将每个图片框的 BorderStyle 属性设置为 None。
       Picture1.BorderStyle = 0
       Picture2.BorderStyle = 0

       '加载位图。
       Picture2.Picture = _
       LoadPicture("c:\Windows\Winlogo.bmp")

       '初始化两个图片框的位置。
       Picture1.Move 0, 0, ScaleWidth - VScroll1.Width, _
       ScaleHeight - HScroll1.Height
       Picture2.Move 0, 0

       '将水平滚动条定位。
       HScroll1.Top = Picture1.Height
       HScroll1.Left = 0
       HScroll1.Width = Picture1.Width

       '将垂直滚动条定位。
       VScroll1.Top = 0
       VScroll1.Left = Picture1.Width
       VScroll1.Height = Picture1.Height

       '设置滚动条的 Max 属性。
       HScroll1.Max = Picture2.Width - Picture1.Width
       VScroll1.Max = Picture2.Height - Picture1.Height

       '判断子图片框是否将充满屏幕。
       '若如此,则无需使用滚动条。
       VScroll1.Visible = (Picture1.Height < _
       Picture2.Height)
       HScroll1.Visible = (Picture1.Width < _
       Picture2.Width)

    End Sub

    水平和垂直滚动条的 Change 事件用来在父图片框中上、下、左、右移动子图片框。请将下列代码添加到两个滚动条控件的 Change 事件中:

    Private Sub HScroll1_Change()
       Picture2.Left = -HScroll1.Value
    End Sub

    Private Sub VScroll1_Change()
       Picture2.Top = -VScroll1.Value
    End Sub

    将子图片框的 Left 和 Top 属性分别设置成水平和垂直滚动条数值的负值,这样,当上、下、左、右滚动时,图形可正确地移动。

    运行时,显示的图形如图 7.26 所示。

    图 7.26   运行时滚动位图

     

    运行时调整窗体大小
    在上例中,窗体的初始大小限制图形的可视大小。在运行时当用户调整窗体大小时,为了调整图形视口应用程序的大小,可将下列代码添加到窗体的 Form_Resize 事件过程中:

    Private Sub Form_Resize()
       '调整窗体大小时,改变 Picture1
       '的尺寸。
       Picture1.Height = Form1.Height
       Picture1.Width = Form1.Width

       '重新初始化图片和滚动条的
       '位置。
       Picture1.Move 0, 0, ScaleWidth - VScroll1.Width, _
       ScaleHeight - HScroll1.Height
       Picture2.Move 0, 0
       HScroll1.Top = Picture1.Height
       HScroll1.Left = 0
       HScroll1.Width = Picture1.Width
       VScroll1.Top = 0
       VScroll1.Left = Picture1.Width
       VScroll1.Height = Picture1.Height
       HScroll1.Max = Picture2.Width - Picture1.Width
       VScroll1.Max = Picture2.Height - Picture1.Width

       '检查是否需要滚动条。
       VScroll1.Visible = (Picture1.Height < _
       Picture2.Height)
       HScroll1.Visible = (Picture1.Width < _
       Picture2.Width)

    End Sub

    展开全文
  • 3、resize用来设置滚动条的交汇处上用于拖动调整元素大小的小控件 组成结构图如下:   一旦发现滚动条的自定义样式,浏览器的默认样式设置将会失效,只使用在css定义的样式。也就意味值能单独只设置scrollbar ...
  • Delphi中实现ListView滚动条的换肤方案概述代码 概述 首先是要骗过WM_...当它为1时,创建一个包含控件全客户区域的Region,再从中CLIP掉滚动条的区域,传给原窗口过程。 然后是WM_HSCROLL和WM_VSCROLL消息。在...

    Delphi中实现ListView滚动条的换肤方案

    概述

    首先是要骗过WM_NCPAINT消息。这个十分容易。WM_NCPAINT消息的wParam是一个区域的句柄。当它不为1时,从它里面CLIP掉滚动条的区域,再传给原窗口过程即可。当它为1时,创建一个包含控件全客户区域的Region,再从中CLIP掉滚动条的区域,传给原窗口过程。
    然后是WM_HSCROLL和WM_VSCROLL消息。在调用原窗口过程之前需要去掉窗口的WS_HSCROLL和WS_VSCROLL样式,否则窗口过程就会在消息中绘制滚动条。调用后需要恢复。同时为避免窗口在WM_STYLECHANGING和WM_STYLECHANGED消息中重绘,也需要截获这两个消息。
    WM_NCCALCSIZE消息也是必须截获的。如果是在处理WM_HSCROLL和WM_VSCROLL消息的过程中响应WM_NCCALCSIZE,则必须去掉WS_HSCROLL和WS_VSCROLL样式。
    然后是WM_ERASEBACKGROUND,WM_MOUSEWHELL消息。在这消息后需要重绘滚动条。
    最重要的莫过于WM_NCHITTEST消息了。因为是自绘,所以滚动条的按下和拖动都必须在这里处理。
    在自己写的滚动条Track函数中,最头疼的莫过于ThumbTrack了。当你计算好滚动到的绝对位置后,用SendMessage(hWnd, WM_XSCROLL, MAKEWPARAM(SB_THUMBTRACK, Pos), 0)发给窗口时,它居然没有反应。这是因为窗口过程不会从消息中取得TrackPos,而是会调用GetScrollInfo的API取得TrackPos(因为前者只有16位)。但是使用SetScrollInfo是没办法设置TrackPos的。虽然你可以用SIF_POS标志让它同时设置Pos和TrackPos,但当Pos等于TrackPos时,窗口过程不会做任何响应。从windows源代码中我们可以了解到,TrackPos并不会为每个窗口保存一份,实际上,在任一时刻最多只有一个滚动条在做ThumbTrack的操作,因此系统只需要用一个全局变量来保存就可以了。
    解决这个问题的办法是HookAPI。在GetScrollInfo中返回我们自己的TrackPos。要注意的是要Hook的不是本模块的API,而是ComCtl32.dll中的GetScrollInfo。因此简单的如往@GetScrollInfo地址写几句跳转的方法是行不通的。必须遍历ComCtl32.dll的pe头。这种技术在很多文章中都有描述。
    不多说了,以下是Delphi代码,要点在前面已有描述,源码中没有做特殊说明。
    使用说明:
    资源中是一张横条的192*16的位图,从左到右依次是:左箭头、右箭头、上箭头、下箭头、左箭头按下、右箭头按下、上箭头按下、下箭头按下、横Thumb条、纵Thumb条、横背景条、纵背景条。
    初始化时,调用GetSkinSB.InitSkinSB(ListView1.Handle);即可。窗口销毁前调用GetSkinSB.UninitSkinSB(ListView1.Handle)。
    虽然也可针对EDIT(TMemo)和其它使用系统滚动条的控件使用此模块,但效果各有差异,需要分别做特殊处理。
    补充:使用此方法后,在调用SetScrollInfo后也必须调用RedrawScrollBars重绘滚动条。Hook本模块的SetScrollInfo API是个好方法。
    原文转载自:https://www.cnblogs.com/spiritofcloud/p/3980382.html

    代码

    unit SkinSB;
    
    interface
    
    uses
      SysUtils, Classes, Windows, Messages, Graphics;
    
    const
      SKINSB_PROP = '{8BC6661E-5880-4353-878D-C3B3784CFC5F}';
    
    type
    
      TBarPosCode = (bpcNone, bpcHArrowL, bpcHArrowR, bpcHPageL, bpcHPageR,
        bpcHThumb, bpcVArrowU, bpcVArrowD, bpcVPageU, bpcVPageD, bpcVThumb,
        bpcCross);
    
      TWindowProc = function(hWnd: hWnd; uMsg: UINT; wParam: wParam; lParam: lParam)
        : LRESULT; stdcall;
    
      PSkinSBInfo = ^TSkinSBInfo;
    
      TSkinSBInfo = packed record
        OldWndProc: TWindowProc;
        Prevent: Boolean; // prevent style change message
        Scrolling: Boolean;
        Style: Cardinal; // real style
        ThumbTrack: Boolean;
        ThumbPos: Integer;
        Tracking: Boolean; // tracking: click arrow or track thumb
      end;
    
      TSkinSB = class
      protected
        FBitmap: TBitmap;
        constructor CreateInstance;
      public
        constructor Create;
        destructor Destroy; override;
        procedure InitSkinSB(H: hWnd);
        procedure UnInitSkinSB(H: hWnd);
        procedure DrawElem(H: hWnd; Code: TBarPosCode; R: TRect; Down: Boolean);
      end;
    
    function GetSkinSB: TSkinSB;
    
    function SkinSBWndProc(hWnd: hWnd; uMsg: UINT; wParam: wParam; lParam: lParam)
      : LRESULT; stdcall;
    function GetSkinSBInfo(hWnd: hWnd): PSkinSBInfo;
    
    implementation
    
    uses
      CommCtrl;
    
    {$R *.res}
    
    var
      l_SkinSB: TSkinSB;
      l_SkinSB_Prop: TATOM;
    
    type
      PImageImportDescriptor = ^TImageImportDescriptor;
    
      TImageImportDescriptor = packed record
        originalFirstThunk: DWORD; // or Characteristics: DWORD
        TimeDateStamp: DWORD;
        ForwarderChain: DWORD;
        Name: DWORD;
        FirstThunk: DWORD;
      end;
    
      PImageChunkData = ^TImageChunkData;
    
      TImageChunkData = packed record
        case Integer of
          0:
            (ForwarderString: DWORD);
          1:
            (Func: DWORD);
          2:
            (ordinal: DWORD);
          3:
            (AddressOfData: DWORD);
      end;
    
      PImageImportByName = ^TImageImportByName;
    
      TImageImportByName = packed record
        Hint: Word;
        Name: array [0 .. 0] of Byte;
      end;
    
    type
      PHookRec = ^THookRec;
    
      THookRec = packed record
        OldFunc: Pointer;
        NewFunc: Pointer;
      end;
    
    var
      _HookGetScrollInfo: THookRec;
    
    procedure HookApiInMod(ImageBase: Cardinal; ApiName: PChar; PHook: PHookRec);
    var
      pidh: PImageDosHeader;
      pinh: PImageNtHeaders;
      pSymbolTable: PIMAGEDATADIRECTORY;
      piid: PImageImportDescriptor;
      pitd_org, pitd_1st: PImageChunkData;
      piibn: PImageImportByName;
      pAPIFunction: Pointer;
      written, oldAccess: DWORD;
    begin
      if ImageBase = 0 then
        Exit;
      pidh := PImageDosHeader(ImageBase);
      pinh := PImageNtHeaders(DWORD(ImageBase) + Cardinal(pidh^._lfanew));
      pSymbolTable := @pinh^.OptionalHeader.DataDirectory[1];
      piid := PImageImportDescriptor(DWORD(ImageBase) +
        pSymbolTable^.VirtualAddress);
      repeat
        pitd_org := PImageChunkData(DWORD(ImageBase) + piid^.originalFirstThunk);
        pitd_1st := PImageChunkData(DWORD(ImageBase) + piid^.FirstThunk);
        repeat
          piibn := PImageImportByName(DWORD(ImageBase) + LPDWORD(pitd_org)^);
          pAPIFunction := Pointer(pitd_1st^.Func);
          if StrComp(ApiName, @piibn^.Name) = 0 then
          begin
            PHook^.OldFunc := pAPIFunction;
            VirtualProtect(@(pitd_1st^.Func), SizeOf(DWORD), PAGE_WRITECOPY,
              oldAccess);
            WriteProcessMemory(GetCurrentProcess(), @(pitd_1st^.Func),
              @PHook^.NewFunc, SizeOf(DWORD), written);
            VirtualProtect(@(pitd_1st^.Func), SizeOf(DWORD), oldAccess, oldAccess);
          end;
          Inc(pitd_org);
          Inc(pitd_1st);
        until pitd_1st^.Func = 0;
        Inc(piid);
      until piid^.FirstThunk + piid^.originalFirstThunk + piid^.ForwarderChain +
        piid^.Name = 0;
    end;
    
    function GetSkinSBInfo(hWnd: hWnd): PSkinSBInfo;
    begin
      Result := PSkinSBInfo(GetProp(hWnd, MAKEINTATOM(l_SkinSB_Prop)));
    end;
    
    function GetSkinSB: TSkinSB;
    begin
      if l_SkinSB = nil then
        l_SkinSB := TSkinSB.CreateInstance;
      Result := l_SkinSB;
    end;
    
    function CalcScrollBarRect(H: hWnd; nBarCode: Cardinal): TRect;
    var
      Style, ExStyle: Cardinal;
    begin
      SetRect(Result, 0, 0, 0, 0);
      Style := GetWindowLong(H, GWL_STYLE);
      ExStyle := GetWindowLong(H, GWL_EXSTYLE);
      if (nBarCode = SB_HORZ) and ((Style and WS_HSCROLL) = 0) then
        Exit;
      if (nBarCode = SB_VERT) and ((Style and WS_VSCROLL) = 0) then
        Exit;
      GetWindowRect(H, Result);
      OffsetRect(Result, -Result.Left, -Result.Top);
      if ((ExStyle and WS_EX_DLGMODALFRAME) <> 0) or
        ((ExStyle and WS_EX_CLIENTEDGE) <> 0) then
      begin
        InflateRect(Result, -GetSystemMetrics(SM_CXEDGE),
          -GetSystemMetrics(SM_CYEDGE));
      end;
      // special: returns the cross
      if nBarCode = SB_BOTH then
      begin
        if ((Style and WS_HSCROLL) = 0) or ((Style and WS_VSCROLL) = 0) then
        begin
          SetRect(Result, 0, 0, 0, 0);
          Exit;
        end;
        Result.Top := Result.Bottom - GetSystemMetrics(SM_CYVSCROLL);
        if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then
          Result.Right := Result.Left + GetSystemMetrics(SM_CXHSCROLL)
        else
          Result.Left := Result.Right - GetSystemMetrics(SM_CXHSCROLL);
        Exit;
      end;
      if nBarCode = SB_HORZ then
      begin
        // if (ExStyle and WS_EX_TOPSCROLLBAR) <> 0 then Result.Bottom := Result.Top + GetSystemMetrics(SM_CYVSCROLL)
        Result.Top := Result.Bottom - GetSystemMetrics(SM_CYVSCROLL);
        if ((Style and WS_VSCROLL) <> 0) then
          Dec(Result.Right, GetSystemMetrics(SM_CYVSCROLL));
      end;
      if nBarCode = SB_VERT then
      begin
        if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then
          Result.Right := Result.Left + GetSystemMetrics(SM_CXHSCROLL)
        else
          Result.Left := Result.Right - GetSystemMetrics(SM_CXHSCROLL);
        if ((Style and WS_HSCROLL) <> 0) then
          Dec(Result.Bottom, GetSystemMetrics(SM_CXHSCROLL));
      end;
    end;
    
    type
      TBarElem = (beArrow1, beBG, beThumb, beArrow2);
      TBarElemRects = array [TBarElem] of TRect;
    
    function CalcBarElemRects(hWnd: hWnd; nBarCode: Integer): TBarElemRects;
    var
      R: TRect;
      SI: TScrollInfo;
      ThumbSize: Integer;
      X, L, H, BlockH, BlockV: Integer;
    begin
      R := CalcScrollBarRect(hWnd, nBarCode);
      SI.cbSize := SizeOf(SI);
      SI.fMask := SIF_ALL;
      GetScrollInfo(hWnd, nBarCode, SI);
      Result[beArrow1] := R;
      Result[beArrow2] := R;
      Result[beBG] := R;
      Result[beThumb] := R;
      if nBarCode = SB_VERT then
      begin
        BlockV := GetSystemMetrics(SM_CYVSCROLL);
        L := Result[beArrow1].Top + BlockV;
        H := Result[beArrow2].Bottom - BlockV;
        Result[beArrow1].Bottom := L;
        Result[beArrow2].Top := H;
        // Inc(L);
        // Dec(H);
        Result[beBG].Top := L;
        Result[beBG].Bottom := H;
      end
      else
      begin
        BlockH := GetSystemMetrics(SM_CXHSCROLL);
        L := Result[beArrow1].Left + BlockH;
        H := Result[beArrow2].Right - BlockH;
        Result[beArrow1].Right := L;
        Result[beArrow2].Left := H;
        // Inc(L);
        // Dec(H);
        Result[beBG].Left := L;
        Result[beBG].Right := H;
      end;
      if SI.nMax - SI.nMin - Integer(SI.nPage) + 1 <= 0 then
      begin
        // max thumb, no thumb
        if nBarCode = SB_VERT then
        begin
          Result[beThumb].Top := L;
          Result[beThumb].Bottom := H;
        end
        else
        begin
          Result[beThumb].Left := L;
          Result[beThumb].Right := H;
        end;
        Exit;
      end;
      ThumbSize := MulDiv(H - L, SI.nPage, SI.nMax - SI.nMin + 1);
      X := L + MulDiv(SI.nTrackPos, H - ThumbSize - L, SI.nMax - Integer(SI.nPage) -
        SI.nMin + 1);
      if nBarCode = SB_VERT then
      begin
        Result[beThumb].Top := X;
        Result[beThumb].Bottom := X + ThumbSize;
      end
      else
      begin
        Result[beThumb].Left := X;
        Result[beThumb].Right := X + ThumbSize;
      end;
    end;
    
    function GetPtBarPos(H: hWnd; Pt: TPoint): TBarPosCode;
    var
      R: TRect;
      BR: TBarElemRects;
    begin
      Result := bpcNone;
      R := CalcScrollBarRect(H, SB_HORZ);
      InflateRect(R, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
      if PtInRect(R, Pt) then
      begin
        BR := CalcBarElemRects(H, SB_HORZ);
        if PtInRect(BR[beArrow1], Pt) then
          Result := bpcHArrowL
        else if PtInRect(BR[beThumb], Pt) then
          Result := bpcHThumb
        else if PtInRect(BR[beArrow2], Pt) then
          Result := bpcHArrowR
        else if Pt.X < BR[beThumb].Left then
          Result := bpcHPageL
        else
          Result := bpcHPageR;
        Exit;
      end;
      R := CalcScrollBarRect(H, SB_VERT);
      InflateRect(R, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
      if PtInRect(R, Pt) then
      begin
        BR := CalcBarElemRects(H, SB_VERT);
        if PtInRect(BR[beArrow1], Pt) then
          Result := bpcVArrowU
        else if PtInRect(BR[beThumb], Pt) then
          Result := bpcVThumb
        else if PtInRect(BR[beArrow2], Pt) then
          Result := bpcVArrowD
        else if Pt.Y < BR[beThumb].Top then
          Result := bpcVPageU
        else
          Result := bpcVPageD;
        Exit;
      end;
    end;
    
    type
      TGetScrollInfoFunc = function(H: hWnd; Code: Integer; var SI: TScrollInfo)
        : Boolean; stdcall;
    
    function _SkinSB_GetScrollInfo(H: hWnd; Code: Integer; var SI: TScrollInfo)
      : Boolean; stdcall;
    var
      P: PSkinSBInfo;
    begin
      Result := TGetScrollInfoFunc(_HookGetScrollInfo.OldFunc)(H, Code, SI);
      P := GetSkinSBInfo(H);
      if (P <> nil) and P^.ThumbTrack and ((SI.fMask and SIF_TRACKPOS) <> 0) then
      begin
        SI.nTrackPos := P^.ThumbPos;
      end;
    end;
    
    { TSkinSB }
    
    constructor TSkinSB.Create;
    begin
      raise Exception.Create('use GetSkinSB.');
    end;
    
    constructor TSkinSB.CreateInstance;
    begin
      inherited;
      _HookGetScrollInfo.OldFunc := nil;
      _HookGetScrollInfo.NewFunc := @_SkinSB_GetScrollInfo;
      HookApiInMod(GetModuleHandle('comctl32.dll'), 'GetScrollInfo',
        @_HookGetScrollInfo);
      FBitmap := TBitmap.Create;
      FBitmap.LoadFromResourceName(hInstance, 'scrollbar');
    end;
    
    destructor TSkinSB.Destroy;
    begin
      FreeAndNil(FBitmap);
      inherited;
    end;
    
    procedure TSkinSB.DrawElem(H: hWnd; Code: TBarPosCode; R: TRect; Down: Boolean);
    var
      Canvas: TCanvas;
    begin
      Canvas := TCanvas.Create;
      try
        Canvas.Handle := GetWindowDC(H);
        try
          case Code of
            bpcHArrowL:
              begin
                if Down then
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 64, 0, SRCCOPY)
                else
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 0, 0, SRCCOPY);
                Exit;
              end;
            bpcHArrowR:
              begin
                if Down then
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 80, 0, SRCCOPY)
                else
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 16, 0, SRCCOPY);
                Exit;
              end;
            bpcHThumb:
              begin
                BitBlt(Canvas.Handle, R.Left, R.Top, 2, 16, FBitmap.Canvas.Handle,
                  128, 0, SRCCOPY);
                BitBlt(Canvas.Handle, R.Right - 2, R.Top, 2, 16,
                  FBitmap.Canvas.Handle, 142, 0, SRCCOPY);
                StretchBlt(Canvas.Handle, R.Left + 2, R.Top, R.Right - R.Left - 4,
                  16, FBitmap.Canvas.Handle, 130, 0, 12, 16, SRCCOPY);
                Exit;
              end;
            bpcHPageL, bpcHPageR:
              begin
                if R.Right - R.Left < 4 then
                begin
                  StretchBlt(Canvas.Handle, R.Left, R.Top, R.Right - R.Left, 16,
                    FBitmap.Canvas.Handle, 160, 0, 16, 16, SRCCOPY);
                end
                else
                begin
                  BitBlt(Canvas.Handle, R.Left, R.Top, 2, 16, FBitmap.Canvas.Handle,
                    160, 0, SRCCOPY);
                  BitBlt(Canvas.Handle, R.Right - 2, R.Top, 2, 16,
                    FBitmap.Canvas.Handle, 174, 0, SRCCOPY);
                  StretchBlt(Canvas.Handle, R.Left + 2, R.Top, R.Right - R.Left - 4,
                    16, FBitmap.Canvas.Handle, 162, 0, 12, 16, SRCCOPY);
                end;
                Exit;
              end;
            bpcVArrowU:
              begin
                if Down then
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 96, 0, SRCCOPY)
                else
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 32, 0, SRCCOPY);
                Exit;
              end;
            bpcVArrowD:
              begin
                if Down then
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 112, 0, SRCCOPY)
                else
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 16,
                    FBitmap.Canvas.Handle, 48, 0, SRCCOPY);
                Exit;
              end;
            bpcVThumb:
              begin
                BitBlt(Canvas.Handle, R.Left, R.Top, 16, 2, FBitmap.Canvas.Handle,
                  144, 0, SRCCOPY);
                BitBlt(Canvas.Handle, R.Left, R.Bottom - 2, 16, 2,
                  FBitmap.Canvas.Handle, 144, 14, SRCCOPY);
                StretchBlt(Canvas.Handle, R.Left, R.Top + 2, 16,
                  R.Bottom - R.Top - 4, FBitmap.Canvas.Handle, 144, 2, 16,
                  12, SRCCOPY);
                Exit;
              end;
            bpcVPageU, bpcVPageD:
              begin
                if R.Bottom - R.Top < 4 then
                begin
                  StretchBlt(Canvas.Handle, R.Left, R.Top, 16, R.Bottom - R.Top,
                    FBitmap.Canvas.Handle, 176, 0, 16, 16, SRCCOPY);
                end
                else
                begin
                  BitBlt(Canvas.Handle, R.Left, R.Top, 16, 2, FBitmap.Canvas.Handle,
                    176, 0, SRCCOPY);
                  BitBlt(Canvas.Handle, R.Left, R.Bottom - 2, 16, 2,
                    FBitmap.Canvas.Handle, 176, 14, SRCCOPY);
                  StretchBlt(Canvas.Handle, R.Left, R.Top + 2, 16,
                    R.Bottom - R.Top - 4, FBitmap.Canvas.Handle, 176, 2, 16,
                    12, SRCCOPY);
                end;
                Exit;
              end;
          end;
          Canvas.Pen.Color := clBlack;
          Canvas.Brush.Color := clWhite;
          Canvas.Rectangle(R);
        finally
          ReleaseDC(H, Canvas.Handle);
        end;
      finally
        Canvas.Handle := 0;
        FreeAndNil(Canvas);
      end;
    end;
    
    procedure TSkinSB.InitSkinSB(H: hWnd);
    var
      PInfo: PSkinSBInfo;
    begin
      PInfo := GetSkinSBInfo(H);
      if PInfo <> nil then
        Exit; // already inited
      New(PInfo);
      PInfo^.OldWndProc := TWindowProc(GetWindowLong(H, GWL_WNDPROC));
      PInfo^.Style := GetWindowLong(H, GWL_STYLE);
      PInfo^.Prevent := False;
      PInfo^.Scrolling := False;
      PInfo^.ThumbTrack := False;
      SetWindowLong(H, GWL_WNDPROC, Cardinal(@SkinSBWndProc));
      SetProp(H, MAKEINTATOM(l_SkinSB_Prop), Cardinal(PInfo));
    end;
    
    procedure TSkinSB.UnInitSkinSB(H: hWnd);
    var
      PInfo: PSkinSBInfo;
    begin
      PInfo := GetSkinSBInfo(H);
      if PInfo = nil then
        Exit; // not inited
      RemoveProp(H, MAKEINTATOM(l_SkinSB_Prop));
      SetWindowLong(H, GWL_WNDPROC, Cardinal(@PInfo^.OldWndProc));
      Dispose(PInfo);
    end;
    
    const
      WM_REPEAT_CLICK = WM_USER + $6478;
    
    procedure OnRepeatClickTimer(hWnd: hWnd; uMsg: UINT; idEvent: UINT;
      dwTime: DWORD); stdcall;
    begin
      KillTimer(0, idEvent);
      PostThreadMessage(MainThreadID, WM_REPEAT_CLICK, 0, 0);
    end;
    
    procedure RedrawScrollBars(hWnd: hWnd);
    var
      RHBar, RVBar, RCross: TRect;
      BR: TBarElemRects;
    begin
      RHBar := CalcScrollBarRect(hWnd, SB_HORZ);
      if not IsRectEmpty(RHBar) then
      begin
        BR := CalcBarElemRects(hWnd, SB_HORZ);
        GetSkinSB.DrawElem(hWnd, bpcHPageL, Rect(BR[beBG].Left, BR[beBG].Top,
          BR[beThumb].Left, BR[beBG].Bottom), False);
        GetSkinSB.DrawElem(hWnd, bpcHPageR, Rect(BR[beThumb].Right, BR[beBG].Top,
          BR[beBG].Right, BR[beBG].Bottom), False);
        GetSkinSB.DrawElem(hWnd, bpcHThumb, BR[beThumb], False);
        GetSkinSB.DrawElem(hWnd, bpcHArrowL, BR[beArrow1], False);
        GetSkinSB.DrawElem(hWnd, bpcHArrowR, BR[beArrow2], False);
      end;
      RVBar := CalcScrollBarRect(hWnd, SB_VERT);
      if not IsRectEmpty(RVBar) then
      begin
        BR := CalcBarElemRects(hWnd, SB_VERT);
        GetSkinSB.DrawElem(hWnd, bpcVPageU, Rect(BR[beBG].Left, BR[beBG].Top,
          BR[beBG].Right, BR[beThumb].Top), False);
        GetSkinSB.DrawElem(hWnd, bpcVPageD, Rect(BR[beBG].Left, BR[beThumb].Bottom,
          BR[beBG].Right, BR[beBG].Bottom), False);
        GetSkinSB.DrawElem(hWnd, bpcVThumb, BR[beThumb], False);
        GetSkinSB.DrawElem(hWnd, bpcVArrowU, BR[beArrow1], False);
        GetSkinSB.DrawElem(hWnd, bpcVArrowD, BR[beArrow2], False);
      end;
      RCross := CalcScrollBarRect(hWnd, SB_BOTH);
      if not IsRectEmpty(RCross) then
      begin
        GetSkinSB.DrawElem(hWnd, bpcCross, RCross, False);
      end;
    end;
    
    procedure TrackBar(hWnd: hWnd; nBarCode: Integer; PosCode: TBarPosCode;
      BarElem: TBarElem; MsgCode: Integer);
    var
      BR: TBarElemRects;
      Msg: tagMSG;
      Pt: TPoint;
      R: TRect;
      ScrollMsg: Cardinal;
      RepeatClick: Boolean;
      idEvent: UINT;
      SI: TScrollInfo;
    
      procedure RefreshRect;
      begin
        BR := CalcBarElemRects(hWnd, nBarCode);
        R := BR[BarElem];
      end;
    
    begin
      RepeatClick := False;
      BR := CalcBarElemRects(hWnd, nBarCode);
      R := BR[BarElem];
      GetScrollInfo(hWnd, nBarCode, SI);
      if nBarCode = SB_HORZ then
        ScrollMsg := WM_HSCROLL
      else
        ScrollMsg := WM_VSCROLL;
      if BarElem = beBG then
      begin
        if PosCode = bpcHPageL then
          R.Right := BR[beThumb].Left
        else if PosCode = bpcHPageR then
          R.Left := BR[beThumb].Right
        else if PosCode = bpcVPageU then
          R.Bottom := BR[beThumb].Top
        else if PosCode = bpcVPageD then
          R.Top := BR[beThumb].Bottom;
      end;
      GetSkinSB.DrawElem(hWnd, PosCode, R, True);
      GetSkinSBInfo(hWnd)^.Tracking := True;
      idEvent := 0;
      try
        SetCapture(hWnd);
        idEvent := SetTimer(0, 0, 1000, @OnRepeatClickTimer);
        while GetCapture = hWnd do
        begin
          if not GetMessage(Msg, 0, 0, 0) then
            Break;
          if (Msg.hWnd = 0) and (Msg.message = WM_REPEAT_CLICK) then
          begin
            GetCursorPos(Pt);
            ScreenToClient(hWnd, Pt);
            if PtInRect(R, Pt) then
            begin
              RepeatClick := True;
              SendMessage(hWnd, ScrollMsg, MsgCode, 0);
              SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);
              RefreshRect;
              GetSkinSB.DrawElem(hWnd, PosCode, R, True);
              // if MsgCode = SB_LINEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + 1, False);
              if MsgCode = SB_PAGEDOWN then
                SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) +
                  Integer(SI.nPage), False);
              // if MsgCode = SB_LINEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - 1, False);
              if MsgCode = SB_PAGEUP then
                SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) -
                  Integer(SI.nPage), False);
              RedrawScrollBars(hWnd);
              SetTimer(0, 0, 80, @OnRepeatClickTimer);
            end;
          end
          else if Msg.hWnd = hWnd then
          begin
            case Msg.message of
              WM_LBUTTONUP:
                begin
                  if RepeatClick then
                    Break;
                  GetCursorPos(Pt);
                  ScreenToClient(hWnd, Pt);
                  if PtInRect(R, Pt) then
                  begin
                    SendMessage(hWnd, ScrollMsg, MsgCode, 0);
                    SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);
                    RefreshRect;
                    // if MsgCode = SB_LINEDOWN then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) + 1, False);
                    if MsgCode = SB_PAGEDOWN then
                      SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) +
                        Integer(SI.nPage), False);
                    // if MsgCode = SB_LINEUP then SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) - 1, False);
                    if MsgCode = SB_PAGEUP then
                      SetScrollPos(hWnd, nBarCode, GetScrollPos(hWnd, nBarCode) -
                        Integer(SI.nPage), False);
                  end;
                  Break;
                end;
            end;
          end;
          DispatchMessage(Msg);
        end;
      finally
        if idEvent <> 0 then
          KillTimer(0, idEvent);
        if IsWindow(hWnd) then
        begin
          if GetCapture = hWnd then
            ReleaseCapture;
          GetSkinSB.DrawElem(hWnd, PosCode, R, False);
          GetSkinSBInfo(hWnd)^.Tracking := False;
        end;
      end;
    end;
    
    procedure TrackThumb(hWnd: hWnd; nBarCode: Integer; PosCode: TBarPosCode;
      BarElem: TBarElem);
    var
      BR: TBarElemRects;
      Msg: tagMSG;
      Pt: TPoint;
      DragX: Integer;
      R: TRect;
      ScrollMsg: Cardinal;
      SI, SI2: TScrollInfo;
      Pos: Integer;
      H, L, ThumbSize, X: Integer;
      Pushed: Boolean;
    
      function ValidDragArea(ARect: TRect; APt: TPoint): Boolean;
      begin
        if nBarCode = SB_HORZ then
          Result := Abs((ARect.Bottom + ARect.Top) div 2 - APt.Y) < 150
        else
          Result := Abs((ARect.Left + ARect.Right) div 2 - APt.X) < 150;
      end;
    
      function CalcPos(ARect: TRect; APt: TPoint; ADragX: Integer): Integer;
      var
        NewX: Integer;
      begin
        if nBarCode = SB_HORZ then
          NewX := APt.X - ADragX
        else
          NewX := APt.Y - ADragX;
        Result := SI.nMin + MulDiv(NewX - L, SI.nMax - Integer(SI.nPage) - SI.nMin +
          1, H - L - ThumbSize);
        if Result < SI.nMin then
          Result := SI.nMin;
        if Result > SI.nMax - Integer(SI.nPage) + 1 then
          Result := SI.nMax - Integer(SI.nPage) + 1;
      end;
    
      procedure UpdateDragBar(ADown: Boolean; APos: Integer = -10000);
      var
        W: Integer;
      begin
        BR := CalcBarElemRects(hWnd, nBarCode);
        R := BR[BarElem];
        if nBarCode = SB_HORZ then
        begin
          if APos <> -10000 then
          begin
            W := R.Right - R.Left;
            if APos < BR[beArrow1].Right then
              APos := BR[beArrow1].Right;
            if APos + W > BR[beArrow2].Left then
              APos := BR[beArrow2].Left - W;
            R.Left := APos;
            R.Right := APos + W;
          end;
          GetSkinSB.DrawElem(hWnd, bpcHPageL, Rect(BR[beBG].Left, BR[beBG].Top,
            R.Left, BR[beBG].Bottom), False);
          GetSkinSB.DrawElem(hWnd, bpcHPageR, Rect(R.Right, BR[beBG].Top,
            BR[beBG].Right, BR[beBG].Bottom), False);
        end
        else
        begin
          if APos <> -10000 then
          begin
            W := R.Bottom - R.Top;
            if APos < BR[beArrow1].Bottom then
              APos := BR[beArrow1].Bottom;
            if APos + W >= BR[beArrow2].Top then
              APos := BR[beArrow2].Top - W - 1;
            R.Top := APos;
            R.Bottom := APos + W;
          end;
          GetSkinSB.DrawElem(hWnd, bpcVPageU, Rect(BR[beBG].Left, BR[beBG].Top,
            BR[beBG].Right, R.Top), False);
          GetSkinSB.DrawElem(hWnd, bpcVPageD, Rect(BR[beBG].Left, R.Bottom,
            BR[beBG].Right, BR[beBG].Bottom), False);
        end;
        GetSkinSB.DrawElem(hWnd, PosCode, R, ADown);
        OutputDebugString(PChar(Format('R=(%d,%d,%d,%d)', [R.Left, R.Top, R.Right,
          R.Bottom])));
      end;
    
    begin
      BR := CalcBarElemRects(hWnd, nBarCode);
      R := BR[BarElem];
      if nBarCode = SB_HORZ then
        ScrollMsg := WM_HSCROLL
      else
        ScrollMsg := WM_VSCROLL;
      SI.cbSize := SizeOf(SI);
      SI.fMask := SIF_ALL;
      GetScrollInfo(hWnd, nBarCode, SI);
      GetCursorPos(Pt);
      ScreenToClient(hWnd, Pt);
      if nBarCode = SB_HORZ then
      begin
        DragX := Pt.X - BR[beThumb].Left;
        ThumbSize := BR[beThumb].Right - BR[beThumb].Left;
        L := BR[beArrow1].Right;
        H := BR[beArrow2].Left;
      end
      else
      begin
        DragX := Pt.Y - BR[beThumb].Top;
        ThumbSize := BR[beThumb].Bottom - BR[beThumb].Top;
        L := BR[beArrow1].Bottom;
        H := BR[beArrow2].Top;
      end;
      { if nBarCode = SB_HORZ then SendMessage(hWnd, WM_SYSCOMMAND, SC_HSCROLL, MAKELPARAM(Pt.X, Pt.Y))
        else SendMessage(hWnd, WM_SYSCOMMAND, SC_VSCROLL, MAKELPARAM(Pt.X, Pt.Y)); }
      GetSkinSBInfo(hWnd)^.Tracking := True;
      UpdateDragBar(True);
      try
        SetCapture(hWnd);
        while GetCapture = hWnd do
        begin
          if not GetMessage(Msg, 0, 0, 0) then
            Break;
          if Msg.hWnd = hWnd then
          begin
            case Msg.message of
              WM_MOUSEMOVE:
                begin
                  Pushed := ValidDragArea(R, Pt);
                  GetCursorPos(Pt);
                  ScreenToClient(hWnd, Pt);
                  if ValidDragArea(R, Pt) then
                  begin
                    Pos := CalcPos(R, Pt, DragX);
                    if nBarCode = SB_HORZ then
                      X := Pt.X - DragX
                    else
                      X := Pt.Y - DragX;
                  end
                  else
                  begin
                    Pos := SI.nPos;
                    X := DragX;
                  end;
                  GetSkinSBInfo(hWnd)^.ThumbPos := Pos;
                  GetSkinSBInfo(hWnd)^.ThumbTrack := True;
                  SendMessage(hWnd, ScrollMsg, MAKEWPARAM(SB_THUMBTRACK, Pos), 0);
                  GetSkinSBInfo(hWnd)^.ThumbTrack := False;
                  UpdateDragBar(Pushed, X);
                end;
              WM_LBUTTONUP:
                begin
                  GetCursorPos(Pt);
                  ScreenToClient(hWnd, Pt);
                  if ValidDragArea(R, Pt) then
                  begin
                    Pos := CalcPos(R, Pt, DragX);
                    SI2.cbSize := SizeOf(SI2);
                    SI2.fMask := SIF_ALL;
                    GetScrollInfo(hWnd, nBarCode, SI2);
                    SI2.nPos := Pos;
                    SI2.nTrackPos := Pos;
                    SetScrollInfo(hWnd, nBarCode, SI2, False);
                    SI2.nTrackPos := 0;
                    SI2.nPos := 0;
                    GetScrollInfo(hWnd, nBarCode, SI2);
                    SendMessage(hWnd, ScrollMsg,
                      MAKEWPARAM(SB_THUMBPOSITION, Pos), 0);
                    SendMessage(hWnd, ScrollMsg, SB_ENDSCROLL, 0);
                  end;
                  Break;
                end;
            end;
          end;
          DispatchMessage(Msg);
        end;
      finally
        if IsWindow(hWnd) then
        begin
          if GetCapture = hWnd then
            ReleaseCapture;
          GetSkinSBInfo(hWnd)^.Tracking := False;
        end;
        UpdateDragBar(False);
      end;
    end;
    
    function SkinSBWndProc(hWnd: hWnd; uMsg: UINT; wParam: wParam;
      lParam: lParam): LRESULT;
    var
      PInfo: PSkinSBInfo;
      Style, ExStyle: Cardinal;
      R, RHBar, RVBar, RCross: TRect;
      Pt: TPoint;
      Rgn, Rgn2: HRGN;
      PR: PRect;
      BR: TBarElemRects;
      XBar, YBar: Integer;
    begin
      PInfo := GetSkinSBInfo(hWnd);
      if PInfo = nil then
        Result := DefWindowProc(hWnd, uMsg, wParam, lParam)
        /// / error!!!
      else
      begin
        case uMsg of
          WM_NCHITTEST:
            begin
              GetCursorPos(Pt);
              ScreenToClient(hWnd, Pt);
              case GetPtBarPos(hWnd, Pt) of
                bpcHArrowL:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackBar(hWnd, SB_HORZ, bpcHArrowL, beArrow1, SB_LINELEFT);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcHArrowR:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackBar(hWnd, SB_HORZ, bpcHArrowR, beArrow2, SB_LINERIGHT);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcHPageL:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                      begin
                        TrackBar(hWnd, SB_HORZ, bpcHPageL, beBG, SB_PAGELEFT);
                        RedrawScrollBars(hWnd);
                      end;
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcHPageR:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                      begin
                        TrackBar(hWnd, SB_HORZ, bpcHPageR, beBG, SB_PAGERIGHT);
                        RedrawScrollBars(hWnd);
                      end;
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcHThumb:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackThumb(hWnd, SB_HORZ, bpcHThumb, beThumb);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
    
                bpcVArrowU:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackBar(hWnd, SB_VERT, bpcVArrowU, beArrow1, SB_LINELEFT);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcVArrowD:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackBar(hWnd, SB_VERT, bpcVArrowD, beArrow2, SB_LINERIGHT);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcVPageU:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                      begin
                        TrackBar(hWnd, SB_VERT, bpcVPageU, beBG, SB_PAGELEFT);
                        RedrawScrollBars(hWnd);
                      end;
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcVPageD:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                      begin
                        TrackBar(hWnd, SB_VERT, bpcVPageD, beBG, SB_PAGERIGHT);
                        RedrawScrollBars(hWnd);
                      end;
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
                bpcVThumb:
                  begin
                    if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
                    begin
                      if GetCapture <> hWnd then
                        TrackThumb(hWnd, SB_VERT, bpcVThumb, beThumb);
                    end;
                    Result := HTNOWhere;
                    Exit;
                  end;
              end;
            end;
          WM_HSCROLL:
            begin
              PInfo^.Scrolling := True;
              Style := GetWindowLong(hWnd, GWL_STYLE);
              PInfo^.Style := Style;
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE,
                  Style and (not(WS_VSCROLL or WS_HSCROLL)));
              finally
                PInfo^.Prevent := False;
              end;
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg,
                wParam, lParam);
              RedrawScrollBars(hWnd);
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE, Style);
              finally
                PInfo^.Prevent := False;
              end;
              PInfo^.Scrolling := False;
              Exit;
            end;
    
          WM_VSCROLL:
            begin
              PInfo^.Scrolling := True;
              Style := GetWindowLong(hWnd, GWL_STYLE);
              PInfo^.Style := Style;
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE,
                  Style and (not(WS_VSCROLL or WS_HSCROLL)));
              finally
                PInfo^.Prevent := False;
              end;
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg,
                wParam, lParam);
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE, Style);
              finally
                PInfo^.Prevent := False;
              end;
              PInfo^.Scrolling := False;
              Exit;
            end;
          WM_STYLECHANGED:
            begin
              if wParam = GWL_STYLE then
              begin
                if PInfo^.Prevent then
                begin
                  Result := 0;
                  Exit;
                end
                else
                begin
                  PInfo^.Style := GetWindowLong(hWnd, GWL_STYLE);
                end;
              end;
            end;
          WM_NCCALCSIZE:
            begin
              Style := GetWindowLong(hWnd, GWL_STYLE);
              ExStyle := GetWindowLong(hWnd, GWL_EXSTYLE);
              XBar := GetSystemMetrics(SM_CXVSCROLL);
              YBar := GetSystemMetrics(SM_CYHSCROLL);
              if PInfo^.Scrolling then
              begin
                PInfo^.Prevent := True;
                try
                  SetWindowLong(hWnd, GWL_STYLE,
                    Style and (not(WS_HSCROLL or WS_VSCROLL))); // real style
                finally
                  PInfo^.Prevent := False;
                end;
              end;
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg,
                wParam, lParam);
              if PInfo^.Scrolling then
              begin
                PR := PRect(lParam);
                if (PInfo^.Style and WS_VSCROLL) <> 0 then
                begin
                  if (ExStyle and WS_EX_LEFTSCROLLBAR) <> 0 then
                    Inc(PR^.Left, XBar)
                  else
                    Dec(PR^.Right, XBar);
                end;
                if (PInfo^.Style and WS_HSCROLL) <> 0 then
                begin
                  Dec(PR^.Bottom, YBar);
                end;
              end;
              if PInfo^.Scrolling then
              begin
                PInfo^.Prevent := True;
                try
                  SetWindowLong(hWnd, GWL_STYLE, Style); // old style
                finally
                  PInfo^.Prevent := False;
                end;
              end;
              Exit;
            end;
          WM_NCPAINT:
            begin
              GetWindowRect(hWnd, R);
              Pt := R.TopLeft;
              if wParam = 1 then
              begin
                Rgn := CreateRectRgn(Pt.X, Pt.Y, Pt.X + R.Right, Pt.Y + R.Bottom);
              end
              else
                Rgn := wParam;
              RHBar := CalcScrollBarRect(hWnd, SB_HORZ);
              OffsetRect(RHBar, Pt.X, Pt.Y);
              if not IsRectEmpty(RHBar) then
              begin
                BR := CalcBarElemRects(hWnd, SB_HORZ);
                GetSkinSB.DrawElem(hWnd, bpcHPageL,
                  Rect(BR[beBG].Left, BR[beBG].Top, BR[beThumb].Left,
                  BR[beBG].Bottom), False);
                GetSkinSB.DrawElem(hWnd, bpcHPageR,
                  Rect(BR[beThumb].Right, BR[beBG].Top, BR[beBG].Right,
                  BR[beBG].Bottom), False);
                GetSkinSB.DrawElem(hWnd, bpcHThumb, BR[beThumb], False);
                GetSkinSB.DrawElem(hWnd, bpcHArrowL, BR[beArrow1], False);
                GetSkinSB.DrawElem(hWnd, bpcHArrowR, BR[beArrow2], False);
              end;
              Rgn2 := CreateRectRgn(RHBar.Left, RHBar.Top, RHBar.Right,
                RHBar.Bottom);
              CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);
              DeleteObject(Rgn2);
              RVBar := CalcScrollBarRect(hWnd, SB_VERT);
              if not IsRectEmpty(RVBar) then
              begin
                BR := CalcBarElemRects(hWnd, SB_VERT);
                GetSkinSB.DrawElem(hWnd, bpcVPageU,
                  Rect(BR[beBG].Left, BR[beBG].Top, BR[beBG].Right,
                  BR[beThumb].Top), False);
                GetSkinSB.DrawElem(hWnd, bpcVPageD,
                  Rect(BR[beBG].Left, BR[beThumb].Bottom, BR[beBG].Right,
                  BR[beBG].Bottom), False);
                GetSkinSB.DrawElem(hWnd, bpcVThumb, BR[beThumb], False);
                GetSkinSB.DrawElem(hWnd, bpcVArrowU, BR[beArrow1], False);
                GetSkinSB.DrawElem(hWnd, bpcVArrowD, BR[beArrow2], False);
              end;
              OffsetRect(RVBar, Pt.X, Pt.Y);
              Rgn2 := CreateRectRgn(RVBar.Left, RVBar.Top, RVBar.Right,
                RVBar.Bottom);
              CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);
              DeleteObject(Rgn2);
              RCross := CalcScrollBarRect(hWnd, SB_BOTH);
              if not IsRectEmpty(RCross) then
              begin
                GetSkinSB.DrawElem(hWnd, bpcCross, RCross, False);
              end;
              OffsetRect(RCross, Pt.X, Pt.Y);
              Rgn2 := CreateRectRgn(RCross.Left, RCross.Top, RCross.Right,
                RCross.Bottom);
              CombineRgn(Rgn, Rgn, Rgn2, RGN_DIFF);
              DeleteObject(Rgn2);
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, Rgn, lParam);
              if wParam = 1 then
                DeleteObject(Rgn);
              Exit;
            end;
          WM_ERASEBKGND:
            begin
              Style := GetWindowLong(hWnd, GWL_STYLE);
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE,
                  Style and (not(WS_VSCROLL or WS_HSCROLL)));
              finally
                PInfo^.Prevent := False;
              end;
    
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg,
                wParam, lParam);
              PInfo^.Prevent := True;
              try
                SetWindowLong(hWnd, GWL_STYLE, Style); // old style
              finally
                PInfo^.Prevent := False;
              end;
              Exit;
            end;
          WM_MOUSEWHEEL, WM_MOUSEMOVE:
            begin
              Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg,
                wParam, lParam);
              if PInfo^.Tracking then
                Exit;
              if (uMsg = WM_MOUSEMOVE) and ((wParam and MK_LBUTTON) = 0) then
                Exit;
              RedrawScrollBars(hWnd);
              Exit;
            end;
        end;
        Result := CallWindowProc(@PInfo^.OldWndProc, hWnd, uMsg, wParam, lParam);
      end;
    end;
    
    initialization
    
    l_SkinSB := nil;
    l_SkinSB_Prop := GlobalAddAtom(SKINSB_PROP);
    
    finalization
    
    if Assigned(l_SkinSB) then
      FreeAndNil(l_SkinSB);
    
    end.
    
    展开全文
  • 当ScrollViewer里包含很多子控件时,默认情况下只能用鼠标手动拖动(或滚轮)滚动条以实现内容的滚动,假如用户是键盘高手,习惯于用Tab键来切换子控件焦点时,即使当前获得焦点的控件可见区域,滚动条也不会...

    当ScrollViewer里包含很多子控件时,默认情况下只能用鼠标手动拖动(或滚轮)滚动条以实现内容的滚动,假如用户是键盘高手,习惯于用Tab键来切换子控件焦点时,即使当前获得焦点的控件在不可见区域,滚动条也不会自动跟随着滚动到相应位置,这个非常不方便,今天在网上看到一个老外的解决办法,代码转贴于此:

            private void _ScrollViewer_GotFocus(object sender, RoutedEventArgs e)
            {
                FrameworkElement element = e.OriginalSource as FrameworkElement;
    
                if (element != null)
                {
                    ScrollViewer scrollViewer = sender as ScrollViewer;
                    scrollViewer.ScrollToVerticalOffset(GetVerticalOffset(element, scrollViewer));
                }
    
            }
    
            private double GetVerticalOffset(FrameworkElement child, ScrollViewer scrollViewer)
            {
                // Ensure the control is scrolled into view in the ScrollViewer.  
                GeneralTransform focusedVisualTransform = child.TransformToVisual(scrollViewer);
                Point topLeft = focusedVisualTransform.Transform(new Point(child.Margin.Left, child.Margin.Top));
                Rect rectangle = new Rect(topLeft, child.RenderSize);
                double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
                return newOffset < 0 ? 0 : newOffset; // no use returning negative offset 
            } 
    

      即:给ScrollViewer的GotFocus事件增加_ScrollViewer_GotFocus处理方法,然后计算当前获取焦点的控件与ScorllViewer的偏移距离,最终得出滚动条应该滚动的偏移量。

    上面这一段代码基本上能解决问题,但是有一个小小的不足:如果有3个输入框从上到下排着,且都在可视范围内,这时如果用鼠标去点击其中一个不是当前获得焦点的输入框,也会触发以上代码,导致滚动条跳动一段距离,这个给用户的感觉好象界面总是在“发神经的”抖动。

    静下来细想一下:其实我们的本意是要解决用户按TAB键的问题,只要在KeyDown或KeyUP事件里处理就行了,没必要在GetFocus时处理,于是有了下面的改进版:

    <UserControl x:Class="SilverlightApplication2.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    
        <Grid x:Name="LayoutRoot" Background="White">
            <ScrollViewer Height="200" Width="200" KeyUp="ScrollViewer_KeyUp">
                <StackPanel>
                    <Button Content="1" Height="20" />
                    <Button Content="2" Height="20" />
                    <Button Content="3" Height="20" />
                    <Button Content="4" Height="20" />
                    <Button Content="5" Height="20" />
                    <Button Content="6" Height="20" />
                    <Button Content="7" Height="20" />
                    <Button Content="8" Height="20" />
                    <Button Content="9" Height="20" />
                    <Button Content="10" Height="20" />
                    <Button Content="11" Height="20" />
                    <Button Content="12" Height="20" />
                    <Button Content="13" Height="20" />
                    <Button Content="14" Height="20" />
                    <Button Content="15" Height="20" />
                    <Button Content="16" Height="20" />
                    <Button Content="17" Height="20" />
                    <Button Content="18" Height="20" />
                    <Button Content="19" Height="20" />
                    <Button Content="20" Height="20" />
                </StackPanel>
            </ScrollViewer>
    
        </Grid>
    </UserControl>
    

      cs部分:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace SilverlightApplication2
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
            }
    
            private void ScrollViewer_KeyUp(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Tab)
                {
                    ScrollViewer scrollViewer = sender as ScrollViewer;
                    FrameworkElement focusedElement = FocusManager.GetFocusedElement() as FrameworkElement;
                    GeneralTransform focusedVisualTransform = focusedElement.TransformToVisual(scrollViewer);
                    Rect rectangle = focusedVisualTransform.TransformBounds(new Rect(new Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize));
                    double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
                    scrollViewer.ScrollToVerticalOffset(newOffset);
                }
    
            }
        }
    }
    

      

    转载于:https://www.cnblogs.com/yjmyzz/archive/2011/10/17/2215896.html

    展开全文
  • 可使用控件ScrollView来做下翻滚动条,但是ScrollView内部只能包含一个控件(可在其内部添加一个layout布局,在布局内部再添加内容)android:layout_width="409dp"android:layout_height="wrap_content"android:layout...

    可使用控件ScrollView来做下翻滚动条,但是ScrollView内部只能包含一个控件(可在其内部添加一个layout布局,在布局内部再添加内容)

    android:layout_width="409dp"

    android:layout_height="wrap_content"

    android:layout_marginStart="1dp"

    app:layout_constraintStart_toStartOf="parent"

    app:layout_constraintTop_toTopOf="parent">

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:src="@mipmap/standard"

    app:layout_constraintStart_toStartOf="parent"

    app:layout_constraintTop_toTopOf="parent" />

    展开全文
  • 如图: 测试的布局采用的...布局文件如下,样式包含基本的控件属性和一个按下选中效果的状态,ImageView外面用的LinearLayout包裹,要不然会上面的RadioGroup里面的控件就都能显示: <Horiz
  •  提示 : vkTextBox水平滚动条暂时关掉: 因为这个还有点小问题... 但是并影响你使用 ;)  本控件包含近20种界面元素控件,全部都包括调用实例:  vkProgressBar进度条控件;  vkCheck支持透明单选框...
  • 除顶部导航、底部选项卡两个控件之外,其它控件都建议放在.mui-content控件内,在Hbuilder中输入mbody,可快速生成包含.mui-content代码块。 一直以为生成的不需要写在mui-content里面 在主体部分增加 ...
  • vs风格Toolbox控件工具箱

    热门讨论 2010-06-09 17:55:13
    9. 计算控件当前状态的内容的总的高度,用于设置滚动条的可见与可见。 10. 暴露一个属性,用于为用户提供当前选中的Item。 11. 声明一个ItemChanged事件,便于用户在选择另一个Item时添加处理的代码。 实现...
  • 1、创建一个包含ScrollPanel和滚动条的用户控件,定义一个List,添加控件时,都添加到这个List中。 2、拖动滚动条时,计算出要显示的控件,清空之前的控件,将要显示的控件从List中取出加入Controls中。这样同时显示...
  • 当所包含的图形超过控件范围时,单独一个 PictureBox 控件无法实现滚动功能─ 因为 PictureBox 控件不能自动添加滚动条。应用程序使用两个图片框。称第一个为平稳父 PictureBox 控件。称第二个为子 Pictu
  • VC界面控件皮肤库(v1.0.1.5)

    千次下载 热门讨论 2013-05-26 14:11:58
    压缩包中包括VS2008和VS2010...包含PNG透明按钮,静态控件,自定义进度条,自定义控制杆,自绘滚动条,完美替换CListCtrl滚动条,支持CListCtrl背景图显示,在CListCtrl中添加进度条,完美替换CRichEditCtrl滚动条等。
  • VC界面控件皮肤库(v1.0.1.0)

    热门讨论 2013-05-21 21:48:51
    调试需要VS2010,只想看效果...包含PNG透明按钮,静态控件,自定义进度条,自定义控制杆,自绘滚动条,完美替换CListCtrl滚动条,支持CListCtrl背景图显示,在CListCtrl中添加进度条,完美替换CRichEditCtrl滚动条等。
  • VC界面控件皮肤库(v1.0.0.5)

    热门讨论 2013-05-04 20:05:42
    此VC界面控件皮肤库我会不断...包含PNG透明按钮,静态控件,自定义进度条,自定义控制杆,自绘滚动条,完美替换CListCtrl滚动条,支持CListCtrl背景图显示,在CListCtrl中添加进度条,完美替换CRichEditCtrl滚动条等。
  • 2.功能:虽能被称为真正容器,但它能为所包裹容器View(甚至非容器)添加垂直滚动条。 默认情况,它只添加垂直滚动条;若同时要添加水平滚动条,就要先包裹horizontalScrollView。3.优点:即使内容超出了...
  • reportx2.7表格控件

    2015-07-13 04:52:13
    2、BottomHeight和RightWidth设为0则reportX没有滚动条,PoleHeight和PoleWidth设为0则表格没有固定标题行列。 3、reportx单元格首列和首行号均为1 4、setpoletext()和getpoletext 参数一为标杆方向横向为0,纵向...
  • Dev Express控件应用之ChartControl

    千次阅读 2015-04-01 11:12:00
    这个控件包含3层,最外面chartControl层、中间XYDiagram层、最里面Series层。 以柱状图为例,各模块分类说明: 1)  这一层之相当于是一个壳子,我们平时在这里面设置属性也多。而且都是些常规属性,...
  • 简介: GroupBox 显示围绕一组控件的框架(带或带标题)。 使用 GroupBox 对窗体上的控件集合进行逻辑分组。 组框是可用于定义控件组的容器控件。 组框的典型用途是包含 ... GroupBox 能显示滚动条。 ...
  • Win32字控件-列表框

    千次阅读 2013-09-28 12:25:47
    LBS_DISABLENOSCROLL 当列表框不包含足够项目移动时,列表框中显示禁用垂直滚动条。如果没有此样式当列表框不包含足够项目时,滚动条隐藏。 LBS_EXTENDEDSEL 使用shift键和鼠标或特定组合键,用户可以选择多个项...
  • 先看个运行效果: * 这个项目实现了复杂表格,表格...网上也找了不少实现这个功能的控件,但是有些能实现刷新和加载更多,有些后台数据源要求合适(比如一般一记录包含了行标题和所有的列,而很多控件是拆分的
  • HorizontalScrollView用于布局容器,可以放置让用户使用滚动条查看视图层次结构,允许视图结构比手机屏幕大.。HorizontalScrollView 是一种 框架布局, 这意味着你可以将包含要滚动完整内容
  • Buttons、Static、Controls with ScrollBar(带滚动条的控件)、Splitter、TabControls、TrackBar & Progress、Misc Controls、Dialog、DataControls 6.1 Buttons 该部分我们演示了Skin++对Delphi的各种类型的按钮...
  • 3)可以显示滚动条。 4)单击可以选中某个单元格。 当然以上只是简单功能描述,DataGrid包含的功能远远大于这些。 那如果让我们实现以上四点,该怎么做呢?这里面我们提到一个概念叫文档视图。意思就是用户...
  • 最近在学习Gallery发现在API ... HorizontalScrollView用于布局容器,可以放置让用户使用滚动条查看视图层次结构,允许视图结构比手机屏幕大.。HorizontalScrollView 是一种 框架布局, 这意味着你可以将包含
  • 选择结构信息等级 --> 根据文件大小选择是否“高速模式” --> 点击“浏览”选择要分析文件 --> 分析完毕后选中结构树中某项 --> 查看数据区对应该项字节数据(或通过滚动条查看某位置字节数据) 注意事项: 1、...
  • 5.配置成功标志: 随便打开一个JAVA文件,点下面的Design页,然后上面会出来一个设计工具条,诸如:Swing,Swing Containers…等,工具条的右上角有用来滚动工具栏的按钮,我们可以将其滚动到最末尾.如果看到有一个OpenSwing...
  • 但是默认情况下滚动条的移动只能通过鼠标直接拖动滚动条来实现,而能通过鼠标的滚轮来实现上下移动,因此需要手动添加代码来实现这个功能。 滚动鼠标的滚轮,触发的是窗体或控件上的 MouseWheel 事件。但是在VS...
  • textarea称文本域,又称文本区,即有滚动条的多行文本输入控件,在网页的提交表单中经常用到。与单行文本框text控件不同,它能通过maxlength属性来限制字数,为此必须寻求其他方法来加以限制以达到预设的需求。 ...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 144
精华内容 57
关键字:

不包含滚动条的控件