首页 > 代码库 > 自绘LISTVIEW的滚动条(Delphi实现)
自绘LISTVIEW的滚动条(Delphi实现)
因项目需要准备对LISTVIEW的滚动条进行自绘。于是在网上搜了一下,问题没解决,却搜出一篇令人不愉快的帖子 。确实,那时候实力是不够的,但现在应该是没问题了,为这个目的才不断磨练自己的。
LISTVIEW控件的滚动条是系统自带的,它不创建窗口。对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)和其它使用系统滚动条的控件使用此模块,但效果各有差异,需要分别做特殊处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | 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 = http://www.mamicode.com/^TImageChunkData; TImageChunkData =http://www.mamicode.com/ 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 . |
补充:使用此方法后,在调用SetScrollInfo后也必须调用RedrawScrollBars重绘滚动条。Hook本模块的SetScrollInfo API是个好方法。在这里就不给出代码了。
自绘LISTVIEW的滚动条(Delphi实现)