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

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

TWinControl = class(TControl)
private
procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
end; procedure TWinControl.WMNCHitTest(var Message: TWMNCHitTest);
begin
with Message do
if (csDesigning in ComponentState) and (FParent <> nil) then
Result := HTCLIENT
else
inherited;
end; procedure TWinControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
begin
case Message.Msg of
WM_SETFOCUS:
begin
Form := GetParentForm(Self);
if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
end;
WM_KILLFOCUS:
if csFocusing in ControlState then Exit;
WM_NCHITTEST:
begin
inherited WndProc(Message);
if (Message.Result = HTTRANSPARENT) and (ControlAtPos(ScreenToClient(
SmallPointToPoint(TWMNCHitTest(Message).Pos)), False) <> nil) then
Message.Result := HTCLIENT;
Exit;
end;
WM_MOUSEFIRST..WM_MOUSELAST:
if IsControlMouseMsg(TWMMouse(Message)) then
begin
{ Check HandleAllocated because IsControlMouseMsg might have freed the
window if user code executed something like Parent := nil. }
if (Message.Result = ) and HandleAllocated then
DefWindowProc(Handle, Message.Msg, Message.wParam, Message.lParam);
Exit;
end;
WM_KEYFIRST..WM_KEYLAST:
if Dragging then Exit;
WM_CANCELMODE:
if (GetCapture = Handle) and (CaptureControl <> nil) and
(CaptureControl.Parent = Self) then
CaptureControl.Perform(WM_CANCELMODE, , );
end;
inherited WndProc(Message);
end;

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

THintWindow = class(TCustomControl)
private
procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
end; procedure THintWindow.WMNCHitTest(var Message: TWMNCHitTest);
begin
Message.Result := HTTRANSPARENT;
end;

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

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

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

procedure TCustomForm.ClientWndProc(var Message: TMessage);

  procedure Default;
begin
with Message do
Result := CallWindowProc(FDefClientProc, ClientHandle, Msg, wParam, lParam);
end; function MaximizedChildren: Boolean;
var
I: Integer;
begin
for I := to MDIChildCount - do
if MDIChildren[I].WindowState = wsMaximized then
begin
Result := True;
Exit;
end;
Result := False;
end; var
DC: HDC;
PS: TPaintStruct;
R: TRect;
begin
with Message do
case Msg of
WM_NCHITTEST:
begin
Default;
if Result = HTCLIENT then Result := HTTRANSPARENT;
end;
WM_ERASEBKGND:
begin
FillRect(TWMEraseBkGnd(Message).DC, ClientRect, Brush.Handle);
{ Erase the background at the location of an MDI client window }
if (FormStyle = fsMDIForm) and (FClientHandle <> ) then
begin
Windows.GetClientRect(FClientHandle, R);
FillRect(TWMEraseBkGnd(Message).DC, R, Brush.Handle);
end;
Result := ;
end;
$3F://!
begin
Default;
if FFormStyle = fsMDIForm then
ShowMDIClientEdge(FClientHandle, (MDIChildCount = ) or
not MaximizedChildren);
end;
WM_PAINT:
begin
DC := TWMPaint(Message).DC;
if DC = then
TWMPaint(Message).DC := BeginPaint(ClientHandle, PS);
try
if DC = then
begin
GetWindowRect(FClientHandle, R);
R.TopLeft := ScreenToClient(R.TopLeft);
MoveWindowOrg(TWMPaint(Message).DC, -R.Left, -R.Top);
end;
PaintHandler(TWMPaint(Message));
finally
if DC = then
EndPaint(ClientHandle, PS);
end;
end;
else
Default;
end;
end;

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

procedure TScreen.SetCursor(Value: TCursor);
var
P: TPoint;
Handle: HWND;
Code: Longint;
begin
if Value <> Cursor then
begin
FCursor := Value;
if Value = crDefault then
begin
{ Reset the cursor to the default by sending a WM_SETCURSOR to the
window under the cursor }
GetCursorPos(P);
Handle := WindowFromPoint(P);
if (Handle <> ) and
(GetWindowThreadProcessId(Handle, nil) = GetCurrentThreadId) then
begin
Code := SendMessage(Handle, WM_NCHITTEST, , LongInt(PointToSmallPoint(P)));
SendMessage(Handle, WM_SETCURSOR, Handle, MakeLong(Code, WM_MOUSEMOVE));
Exit;
end;
end;
Windows.SetCursor(Cursors[Value]);
end;
Inc(FCursorCount);
end;

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

procedure TCustomCombo.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
ComboProc: Pointer);
var
Point: TPoint;
Form: TCustomForm;
begin
try
with Message do
begin
case Msg of
WM_SETFOCUS:
begin
Form := GetParentForm(Self);
if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
end;
WM_KILLFOCUS:
if csFocusing in ControlState then Exit;
WM_NCHITTEST:
if csDesigning in ComponentState then
begin
Result := HTTRANSPARENT;
Exit;
end;
CN_KEYDOWN, CN_CHAR, CN_SYSKEYDOWN, CN_SYSCHAR:
begin
WndProc(Message);
Exit;
end;
end;
Result := CallWindowProc(ComboProc, ComboWnd, Msg, WParam, LParam);
if (Msg = WM_LBUTTONDBLCLK) and (csDoubleClicks in ControlStyle) then
DblClick;
end;
except
Application.HandleException(Self);
end;
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. 道格拉斯—普克(Douglas一Peukcer)节点抽稀算法

    Douglas一Peukcer算法由D.Douglas和T.Peueker于1973年提出,简称D一P算法,是眼下公认的线状要素化简经典算法.现有的线化简算法中,有相当一部分都是在该算法基础上进行改进 ...

  2. hdu4722之简单数位dp

    Good Numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tot ...

  3. 使用Xshell生成key,避免password登录linux

    我们通常Xshell使用命令ssh user@ip远程登录linux,这将促使我们进入password更麻烦的,通缉免费password日志的话,我们可以生成相应的key.然后把遥控器server上, ...

  4. android4.0蓝牙使能的详细解析 (转载)

    此博客是转载过来的哦... 给自己博客定几个部分: (1)写在前面的话:一些写博客时的废话. (2)内容简介:把文章的主要内容或者核心部分作一个框架性的概括,以方便大家阅读. (3)正文:这个不需要解 ...

  5. 总线接口与计算机通信(三)UART起止式异步通用串行数据总线

    串口简介 1. 什么是串口? 串口是计算机上一种非常通用的设备通信的协议.串口通信的概念非常简单,串口按位(bit) 发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送 ...

  6. 认识到了x64程序的必要性

    假如我做一个程序,在运行过程中需要使用一个Map,然而这个Map存储了超多信息的话,系统内存不够就会崩溃了.以前的解决方案可能是把内容存储在一个文件/数据库里,但是有内存岂不是更方便.更直截了当!

  7. 基于visual Studio2013解决面试题之1310随机数

     题目

  8. 七牛用户如何将视频转码成普清高清来适应不同的手机端或者web端

    Qiniu 七牛问题解答 非常多人会用到七牛视频转码问题,要将视频转码成适用于各种终端的视频,也有的用户对转码服务的码率,帧率,分辨率等理解不多.不知道该怎样设置这些參数.以下我给大家科普一下. 问题 ...

  9. java 基于JDK中的源码总结下String二

    申明:转载请注明出处,如有商用目的请务必知会本人,感谢. 上一篇文章:http://blog.csdn.net/ts1122/article/details/8738336,介绍了String一些易错 ...

  10. HDU 3480 DP+斜率优化

    题意:给你n个数字,然后叫你从这些数字中选出m堆,使得每一堆的总和最小,一堆的总和就是这一堆中最大值减去最小值的平方,最后要使得所有堆加起来的总和最小. 思路:对这些数字排序之后,很容易想到DP解法, ...