前提:WM_NCHITTEST是很重要的,只要鼠标在活动,Windows无时无刻在发这个消息进行探测。

--------------------------------------------------------------------------------

  1. TWinControl = class(TControl)
  2. private
  3. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  4. end;
  5.  
  6. procedure TWinControl.WMNCHitTest(var Message: TWMNCHitTest);
  7. begin
  8. with Message do
  9. if (csDesigning in ComponentState) and (FParent <> nil) then
  10. Result := HTCLIENT
  11. else
  12. inherited;
  13. end;
  14.  
  15. procedure TWinControl.WndProc(var Message: TMessage);
  16. var
  17. Form: TCustomForm;
  18. begin
  19. case Message.Msg of
  20. WM_SETFOCUS:
  21. begin
  22. Form := GetParentForm(Self);
  23. if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
  24. end;
  25. WM_KILLFOCUS:
  26. if csFocusing in ControlState then Exit;
  27. WM_NCHITTEST:
  28. begin
  29. inherited WndProc(Message);
  30. if (Message.Result = HTTRANSPARENT) and (ControlAtPos(ScreenToClient(
  31. SmallPointToPoint(TWMNCHitTest(Message).Pos)), False) <> nil) then
  32. Message.Result := HTCLIENT;
  33. Exit;
  34. end;
  35. WM_MOUSEFIRST..WM_MOUSELAST:
  36. if IsControlMouseMsg(TWMMouse(Message)) then
  37. begin
  38. { Check HandleAllocated because IsControlMouseMsg might have freed the
  39. window if user code executed something like Parent := nil. }
  40. if (Message.Result = ) and HandleAllocated then
  41. DefWindowProc(Handle, Message.Msg, Message.wParam, Message.lParam);
  42. Exit;
  43. end;
  44. WM_KEYFIRST..WM_KEYLAST:
  45. if Dragging then Exit;
  46. WM_CANCELMODE:
  47. if (GetCapture = Handle) and (CaptureControl <> nil) and
  48. (CaptureControl.Parent = Self) then
  49. CaptureControl.Perform(WM_CANCELMODE, , );
  50. end;
  51. inherited WndProc(Message);
  52. end;

虽然WndProc具有优先权,但是却刻意调用了inherited WndProc(Message);,因此会首先执行TWinControl.WMNCHitTest,如果发现是透明并且能找到一个TControl,那么就算击中了HTCLIENT
--------------------------------------------------------------------------------

  1. THintWindow = class(TCustomControl)
  2. private
  3. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  4. end;
  5.  
  6. procedure THintWindow.WMNCHitTest(var Message: TWMNCHitTest);
  7. begin
  8. Message.Result := HTTRANSPARENT;
  9. end;

--------------------------------------------------------------------------------

  1. TScrollBox = class(TScrollingWinControl)
  2. private
  3. procedure WMNCHitTest(var Message: TMessage); message WM_NCHITTEST;
  4. end;
  5.  
  6. procedure TScrollBox.WMNCHitTest(var Message: TMessage);
  7. begin
  8. DefaultHandler(Message); // TScrollBox和TScrollingWinControl都没有覆盖DefaultHandler函数,因此它会调用TWinControl.DefaultHandler
  9. end;

--------------------------------------------------------------------------------

  1. procedure TCustomForm.ClientWndProc(var Message: TMessage);
  2.  
  3. procedure Default;
  4. begin
  5. with Message do
  6. Result := CallWindowProc(FDefClientProc, ClientHandle, Msg, wParam, lParam);
  7. end;
  8.  
  9. function MaximizedChildren: Boolean;
  10. var
  11. I: Integer;
  12. begin
  13. for I := to MDIChildCount - do
  14. if MDIChildren[I].WindowState = wsMaximized then
  15. begin
  16. Result := True;
  17. Exit;
  18. end;
  19. Result := False;
  20. end;
  21.  
  22. var
  23. DC: HDC;
  24. PS: TPaintStruct;
  25. R: TRect;
  26. begin
  27. with Message do
  28. case Msg of
  29. WM_NCHITTEST:
  30. begin
  31. Default;
  32. if Result = HTCLIENT then Result := HTTRANSPARENT;
  33. end;
  34. WM_ERASEBKGND:
  35. begin
  36. FillRect(TWMEraseBkGnd(Message).DC, ClientRect, Brush.Handle);
  37. { Erase the background at the location of an MDI client window }
  38. if (FormStyle = fsMDIForm) and (FClientHandle <> ) then
  39. begin
  40. Windows.GetClientRect(FClientHandle, R);
  41. FillRect(TWMEraseBkGnd(Message).DC, R, Brush.Handle);
  42. end;
  43. Result := ;
  44. end;
  45. $3F://!
  46. begin
  47. Default;
  48. if FFormStyle = fsMDIForm then
  49. ShowMDIClientEdge(FClientHandle, (MDIChildCount = ) or
  50. not MaximizedChildren);
  51. end;
  52. WM_PAINT:
  53. begin
  54. DC := TWMPaint(Message).DC;
  55. if DC = then
  56. TWMPaint(Message).DC := BeginPaint(ClientHandle, PS);
  57. try
  58. if DC = then
  59. begin
  60. GetWindowRect(FClientHandle, R);
  61. R.TopLeft := ScreenToClient(R.TopLeft);
  62. MoveWindowOrg(TWMPaint(Message).DC, -R.Left, -R.Top);
  63. end;
  64. PaintHandler(TWMPaint(Message));
  65. finally
  66. if DC = then
  67. EndPaint(ClientHandle, PS);
  68. end;
  69. end;
  70. else
  71. Default;
  72. end;
  73. end;

--------------------------------------------------------------------------------

  1. procedure TScreen.SetCursor(Value: TCursor);
  2. var
  3. P: TPoint;
  4. Handle: HWND;
  5. Code: Longint;
  6. begin
  7. if Value <> Cursor then
  8. begin
  9. FCursor := Value;
  10. if Value = crDefault then
  11. begin
  12. { Reset the cursor to the default by sending a WM_SETCURSOR to the
  13. window under the cursor }
  14. GetCursorPos(P);
  15. Handle := WindowFromPoint(P);
  16. if (Handle <> ) and
  17. (GetWindowThreadProcessId(Handle, nil) = GetCurrentThreadId) then
  18. begin
  19. Code := SendMessage(Handle, WM_NCHITTEST, , LongInt(PointToSmallPoint(P)));
  20. SendMessage(Handle, WM_SETCURSOR, Handle, MakeLong(Code, WM_MOUSEMOVE));
  21. Exit;
  22. end;
  23. end;
  24. Windows.SetCursor(Cursors[Value]);
  25. end;
  26. Inc(FCursorCount);
  27. end;

--------------------------------------------------------------------------------

  1. procedure TCustomCombo.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  2. ComboProc: Pointer);
  3. var
  4. Point: TPoint;
  5. Form: TCustomForm;
  6. begin
  7. try
  8. with Message do
  9. begin
  10. case Msg of
  11. WM_SETFOCUS:
  12. begin
  13. Form := GetParentForm(Self);
  14. if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
  15. end;
  16. WM_KILLFOCUS:
  17. if csFocusing in ControlState then Exit;
  18. WM_NCHITTEST:
  19. if csDesigning in ComponentState then
  20. begin
  21. Result := HTTRANSPARENT;
  22. Exit;
  23. end;
  24. CN_KEYDOWN, CN_CHAR, CN_SYSKEYDOWN, CN_SYSCHAR:
  25. begin
  26. WndProc(Message);
  27. Exit;
  28. end;
  29. end;
  30. Result := CallWindowProc(ComboProc, ComboWnd, Msg, WParam, LParam);
  31. if (Msg = WM_LBUTTONDBLCLK) and (csDoubleClicks in ControlStyle) then
  32. DblClick;
  33. end;
  34. except
  35. Application.HandleException(Self);
  36. end;
  37. end;

--------------------------------------------------------------------------------

Delphi对WM_NCHITTEST消息的处理的更多相关文章

  1. [转]关于WM_NCHITTEST消息

    http://www.cnblogs.com/GnagWang/archive/2010/09/12/1824394.html 我为了移动一个无标题栏的窗体,使用了WM_NCHITTEST消息,这个消 ...

  2. 对WM_NCHITTEST消息的了解+代码实例进行演示(消息产生消息,共24个枚举值)

    这个消息比较实用也很关键,它代表非显示区域命中测试.这个消息优先于所有其他的显示区域和非显示区域鼠标消息.其中lParam参数含有鼠标位置的x和y屏幕坐标,wParam 这里没有用. Windows应 ...

  3. 终于懂了:Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了(有了这个,就有了主动)

    Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了,跟Windows消息虽然尽量保持一致,但其实相互没有特别大的关系.有了这个,就有了主动,带不带句柄完全看需要. 比如这个结构就带句 ...

  4. 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)

    1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...

  5. 关于WM_NCHITTEST消息

    我为了移动一个无标题栏的窗体,使用了WM_NCHITTEST消息,这个消息大概如下: 通常,我们拖动对话框窗口的标题栏来移动窗口,但有时候,我们想通过鼠标在客户区上拖动来移动窗口. 一个容易想到的方案 ...

  6. Delphi 实现无窗口移动(发WM_NCHITTEST消息计算,然后再发WM_SYSCOMMAND消息,带参数SC_DRAGMOVE)

    procedure imgListMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer) ...

  7. Delphi中window消息截获的实现方式(2)

    Delphi是Borland公司提供的一种全新的WINDOWS编程开发工具.由于它采用了具有弹性的和可重用的面向对象Pascal(object-orientedpascal)语言,并有强大的数据库引擎 ...

  8. QT中异形窗口的绘制(winEvent处理WM_NCHITTEST消息)

    这里讨论的只是Windows平台上的实现. 在QT中绘制异形窗口,只要设定 windowFlag 为 CustomizeWindowHint,再结合setMask()就可以做出各种奇形怪状的窗口.相对 ...

  9. Delphi中的消息截获(六种方法:Hook,SubClass,Override WndProc,Message Handler,RTTI,Form1.WindowProc:=@myfun)good

    Windows是一个基于消息驱动的系统,因此,在很多时候,我们需要截获一些消息然后自己进行处理.而VCL系统又有一些特定的消息.下面对我所了解的delphi环境中截获消息进行一些总结.      就个 ...

随机推荐

  1. 枚举+搜索 hdu-4431-Mahjong

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4431 题目大意: 给一副牌,求出所有能糊的牌. 解题思路: 枚举每一张牌,看能不能糊. 因为一共只有 ...

  2. 6.6.2 自己主动泛型化(automatic generalization)

    6.6.2 自己主动泛型化(automatic generalization) 在这一章,我们已经实现了几个 F# 的高阶函数.也看到了在 F# 和 C# 中并排的实现.F# 实现的非常重要方面,是我 ...

  3. 【通信框架】Apache的开源通信框架thrift概述

    在阅读的过程中有不论什么问题.欢迎一起交流 邮箱:1494713801@qq.com    QQ:1494713801 一.作用 Thrift("Scalable Cross-Languag ...

  4. VirtualBox安装及使用说明和虚拟机安装XP系统图文教程

    virtualbox是一款开源的虚拟机软件,它能够支持多种操作系统的安装如:Solaris.Windows.DOS.Linux.OS/2 Warp.BSD等系统作为client操作系统,而且最新版本号 ...

  5. android怎样实现自动点击功能

    一个按钮之类的控件的自动点击的话,可以定时调用 button.performClick();

  6. MSSQL - 存储过程取出5条热点新闻

    USE [DB_News] GO /****** Object: StoredProcedure [dbo].[SelectHotNews] Script Date: 2015/7/8 13:34:4 ...

  7. node-inspector使用

    nodejs.gulp调试工具node-inspector使用 俗话说欲善其功,必先利其器. 作为目前新型的Web Server开发栈倍受开发者关注的Nodejs来说,调试技术是学习开发的基石,所以对 ...

  8. OnClick事件的Sender参数的前世今生——TWinControl.WinProc优先捕捉到鼠标消息,然后使用IsControlMouseMsg函数进行消息转发给图形子控件(意外发现OnClick是由WM_LBUTTONUP触发的)

    这是一个再普通不过的Button1Click执行体: procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('I am B ...

  9. guava之Joiner 和 Splitter(转)

    最近在给客户准备一个Guava的分享,所以会陆续的更新关于Guava更多的细节分享.本文将记录Guava中得字符串处理Joiner(连接)和Splitter(分割)处理. Joiner 首先我们来看看 ...

  10. C++学习之路—继承与派生(一):基本概念与基类成员的访问属性

    (本文根据<c++程序设计>(谭浩强)总结而成,整理者:华科小涛@http://www.cnblogs.com/hust-ghtao,转载请注明) 1   基本思想与概念 在传统的程序设计 ...