注意,这些函数只有Private一种形式(也就是不允许覆盖,但仍在动态表格中)(特别注意,这里居然没有WM_PAINT函数)

  TControl = class(TComponent)
private
// 15个私有消息处理,大多是鼠标消息。注意,消息函数大多只是一个中介,且TWinControl并不重写。
procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;
procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK;
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP;
//
procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;
procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED; // 重新计算最大化最小化的限制和坞里的尺寸
procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU; // 真正展开右键菜单,其子类虽然覆盖这个函数,但反而只是帮助发送而已(发送给图形控件,为其增加右键菜单功能)。
// 17个组件事件(大多是简单函数,通知某件事情,一般没有实际内容)
// CM_显示函数
procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED; // 显示属性被改变了,那么要调用InvalidateControl重画自己。fixme 不明白这句为什么一定要这样调用,而不是执行Invalidate函数
procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; // 3个函数都简单调用Invalidate; 但是注意,它有可能调用子类TWinControl的Invalidate函数
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED;
procedure CMParentBiDiModeChanged(var Message: TMessage); message CM_PARENTBIDIMODECHANGED;
// 颜色字体
procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
procedure CMSysFontChanged(var Message: TMessage); message CM_SYSFONTCHANGED; // 调用SetFont
procedure CMParentColorChanged(var Message: TMessage); message CM_PARENTCOLORCHANGED;
procedure CMParentShowHintChanged(var Message: TMessage); message CM_PARENTSHOWHINTCHANGED; // 调用 SetShowHint
procedure CMHintShow(var Message: TMessage); message CM_HINTSHOW;
procedure CMHitTest(var Message: TCMHitTest); message CM_HITTEST; // 测试鼠标消息对子控件是否起作用
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER; // important 有趣,给父控件发送CM_MOUSEENTER,为什么要依赖它来处理?
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST; // important5 什么都不做,消息结果为未处理
procedure CMFloat(var Message: TCMFloat); message CM_FLOAT;
procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL; // 给父控件发送CM_MOUSEWHEEL
end;

同时把它的WndProc列出来,这样它能处理的消息就齐了:

procedure TControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
KeyState: TKeyboardState;
WheelMsg: TCMMouseWheel;
begin
if (csDesigning in ComponentState) then
begin
Form := GetParentForm(Self);
if (Form <> nil) and (Form.Designer <> nil) and
Form.Designer.IsDesignMsg(Self, Message) then Exit //消息由窗体来处理
end;
//窗体可以为其拥有的组件来处理键盘消息
if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then
begin
Form := GetParentForm(Self);
if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
end
// important 图形控件的鼠标处理都在这里
else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
begin
//如果组件不可以接受和处理双击消息,就将双击消息映射为单击消息。
if not (csDoubleClicks in ControlStyle) then
case Message.Msg of
WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
end;
case Message.Msg of
WM_MOUSEMOVE:
Application.HintMouseMessage(Self, Message); // 如果是鼠标移动的消息,则出现hint窗口
WM_LBUTTONDOWN, WM_LBUTTONDBLCLK: // 如果是左键被按下,或者双击,如果是自动拖动模式,则开始拖动,并将左键按下的状态加入组件的状态。
begin
if FDragMode = dmAutomatic then
begin
BeginAutoDrag;
Exit;
end;
Include(FControlState, csLButtonDown); // important 为图形控件(也可为Win控件)增加鼠标点击状态。点击Button就会执行到这里来。
end;
WM_LBUTTONUP:
Exclude(FControlState, csLButtonDown); //如果是左键放开,则将左键按下的状态剔除。
else
with Mouse do
if WheelPresent and (RegWheelMessage <> ) and //如果鼠标有滚轮,并且滚轮滑动时发出了消息
(Message.Msg = RegWheelMessage) then
begin
GetKeyboardState(KeyState); // API,将256虚拟键的状态拷贝到缓存中去
with WheelMsg do //填充记录
begin
Msg := Message.Msg;
ShiftState := KeyboardStateToShiftState(KeyState);
WheelDelta := Message.WParam;
Pos := TSmallPoint(Message.LParam);
end;
MouseWheelHandler(TMessage(WheelMsg)); // 类函数,派发鼠标滚轮的消息
Exit;
end;
end;
end
else if Message.Msg = CM_VISIBLECHANGED then
with Message do
SendDockNotification(Msg, WParam, LParam);
Dispatch(Message); // 到了这里,已经无法再使用WndProc方法向父类传递消息了,所以使用Dispatch。而且必定向上传递(一般情况下TControl的父类不会不响应这些消息)
end;

当然还有DefaultHandler:

procedure TControl.DefaultHandler(var Message);
var
P: PChar;
begin
with TMessage(Message) do
case Msg of
WM_GETTEXT:
begin
if FText <> nil then P := FText else P := '';
Result := StrLen(StrLCopy(PChar(LParam), P, WParam - ));
end;
WM_GETTEXTLENGTH:
if FText = nil then Result := else Result := StrLen(FText);
WM_SETTEXT:
begin
P := StrNew(PChar(LParam));
StrDispose(FText);
FText := P;
SendDockNotification(Msg, WParam, LParam);
end;
end;
end;

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

我还特意查了一下Delphi 5.0和Delphi 7.0的差别,主要就在于WM_MOUSEWHEEL消息的处理。

在Delphi 5.0里只有这个处理函数:

procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL;

procedure TWinControl.CMMouseWheel(var Message: TCMMouseWheel);
begin
with Message do
begin
Result := ;
if DoMouseWheel(ShiftState, WheelDelta, SmallPointToPoint(Pos)) then
Message.Result :=
else if Parent <> nil then
with TMessage(Message) do
Result := Parent.Perform(CM_MOUSEWHEEL, WParam, LParam);
end;
end;

但是在Delphi 7.0里有两个消息处理函数:

procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;

procedure TControl.WMMouseWheel(var Message: TWMMouseWheel);
begin
if not Mouse.WheelPresent then
begin
Mouse.FWheelPresent := True;
Mouse.SettingChanged(SPI_GETWHEELSCROLLLINES);
end;
TCMMouseWheel(Message).ShiftState := KeysToShiftState(Message.Keys);
MouseWheelHandler(TMessage(Message));
if Message.Result = then inherited;
end; procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL; procedure TControl.CMMouseWheel(var Message: TCMMouseWheel);
begin
with Message do
begin
Result := ;
if DoMouseWheel(ShiftState, WheelDelta, SmallPointToPoint(Pos)) then
Message.Result :=
else if Parent <> nil then
with TMessage(Message) do
Result := Parent.Perform(CM_MOUSEWHEEL, WParam, LParam);
end;
end;

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

特意查了一下XE5,它对WM_消息的处理还是15个,这也难怪,TControl能处理鼠标消息已经是法外开恩了,不能也不需要处理无限多的WM_消息。

话说,如果我把父控件的键盘以及其它WM_消息强行转发给TControl子控件会怎么样呢?这个问题值得思考。。。

TControl的消息覆盖函数大全(15个WM_函数和17个CM_函数,它的WndProc就处理鼠标与键盘消息)的更多相关文章

  1. MFC控件编程之鼠标跟键盘消息

    MFC控件编程之鼠标跟键盘消息 在MFC中鼠标消息.键盘消息我们很常用.所以说一下. 鼠标消息分为客户区消息.跟非客户区消息. 一丶客户区消息 我们可以处理消息.来进行我们相应的函数即可. MFC添加 ...

  2. .NET下如何拦截鼠标、键盘消息?Win32NET来帮你

    Win32NET是一个Win32API的.NET下封装的类库,包含: 1: 常用win32的API的net封装 2:鼠标.键盘.热键hook钩子模块, 3:模拟键盘输入文字(支持各种字符文字.不同语言 ...

  3. TWinControl与TControl的覆盖函数(TWinControl对TControl的10个消息覆盖函数,17个覆盖函数,私有虚函数仍可多态)

    手工找出来,对比一下,有助于VCL框架的理解.----------------------------------------------------------------------------- ...

  4. orale 函数大全[转]

    oracle函数大全 http://wenku.baidu.com/link?url=bXaGsnn8iN264GB8ec48IUPg5eRGDKAyAiSw0OBKL1I0mBVG549-2u9HT ...

  5. WinAPI——钩子函数大全3

    函数原形:LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam); 参数: code:指示一个代码,被 ...

  6. WinAPI——钩子函数大全2

    CallNextHookEx 函数功能:该函数发送挂钩信息给当前挂钩链中的下一个挂钩处理过程,一个挂钩处理过程可在对该挂钩信息进行处理之前或之后调用本函数. 函数原形:LRESULT CallNext ...

  7. delphi字符串函数大全

    转帖:delphi字符串函数大全 2009-11-17 16:43:55 分类: delphi字符串函数大全 ━━━━━━━━━━━━━━━━━━━━━首部 function StringToGUID ...

  8. TWinControl的消息覆盖函数大全(41个WM_函数和31个CM_函数,它的WndProc就处理鼠标(转发)、键盘(取消拖动)、焦点、和WM_NCHITTEST一共4类消息)

    注意,这些函数只有Private一种形式(也就是不允许覆盖,但仍在动态表格中): 其中TWinControl对TControl有10个消息进行了覆盖(红色标记),其中有2个是WM_消息,8个是CM_消 ...

  9. SendMessage函数的常用消息及其应用大全

    来源:http://www.360doc.com/content/09/0814/10/19147_4907488.shtml,非常全面的解释. 文本框控件通常用于输入和编辑文字.它属于标准 Wind ...

随机推荐

  1. 【E2LSH源代码分析】p稳定分布LSH算法初探

    上一节,我们分析了LSH算法的通用框架,主要是建立索引结构和查询近似近期邻.这一小节,我们从p稳定分布LSH(p-Stable LSH)入手,逐渐深入学习LSH的精髓,进而灵活应用到解决大规模数据的检 ...

  2. 异常:未能载入文件或程序集”DAL”或它的某一个依赖项——解决的方法

    以下是我再使用抽象工厂+反射重构机房时,在Factoy中出现了以下一个问题: 去网上查了一下资料,发现这是一个非常普遍的问题,它出现的原因主要有两种: 第一种: 载入DLL路径错误.解决的方法是调整D ...

  3. cocos2dx 在windows上实现键盘输入

    cocos2d主要面向的是触摸屏幕设备的,在WINDOWS下的定位感觉多多少少就是相当于一个模拟器,因此并没有太多的PC下重要的键盘支持.然而响应键盘消息对于调试来说可以提供不少方便.下边就通过更改c ...

  4. 技术回归01-Windows内存分配工具

    很久没有写技术方面的东西了,这半年主要是在学习别人的东西,对自己提高比较大,算是一次技术回笼吧,这次学习之旅目的是结束技术方面的专注,开始向应用方面找突破口,也就是完成技术积累或者为技术的积累做坚实的 ...

  5. jquery mobile切换页面的几种方法

    jquery mobile切换页面的几种方法 - 不厚道青蛙之焦油潭 - 博客频道 - CSDN.NET jquery mobile切换页面的几种方法 分类: phonegap html5 2012- ...

  6. 《Head First 设计模式》学习笔记——状态模式

    在软件开发过程中.应用程序可能会依据不同的情况作出不同的处理. 最直接的解决方式是将这些全部可能发生的情况全都考虑到.然后使用if... ellse语句来做状态推断来进行不同情况的处理. 可是对复杂状 ...

  7. UVA 6480 Zombie Invasion(模拟退火)

    A group of survivors has arrived by helicopter to an isolated island. The island is made up of a lon ...

  8. 【AllJoyn专题】基于AllJoyn和Yeelink的传感器数据上传与指令下行的研究

    接触高通物联网框架AllJoyn不太久,但确是被深深地吸引了.在我看来,促进我深入学习的原因有三点:一.AllJoyn开源,对开源的软硬件总会有种莫名的喜爱,虽然或许不会都深入下去:二.顺应潮流,物联 ...

  9. 第三天学习内容 if--else

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  10. TCP/IP协议的编写《转载》

    基于HHARM9-EDU的TCP/IP(UDP)协议的实现 原文网址:http://blog.csdn.net/lhj0503/article/details/3323788 摘 要:嵌入式技术的发展 ...