注意,这些函数只有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. VMware machine里的文件

    .nvram——虚拟机BIOS或EFI配置文件. .vmdk——虚拟磁盘特性文件,是存放虚拟磁盘当前状况和上次执行快照时的状况之间的差异的快照文件. .vmsd——虚拟机快照,包含虚拟机快照信息的数据 ...

  2. 操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox

    原文 操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox 很久没自己写写心得日志与大家分享了,一方面是自己有点忙,一方面是自己有点懒,没有及时总结.因为实践是经验的来源,总结 ...

  3. Principle of Computing (Python)学习笔记(5) BFS Searching + Zombie Apocalypse

    1 Generators   Generator和list comprehension非常类似 Generators are a kind of iterator that are defined l ...

  4. word2vec 中的数学原理具体解释(一)文件夹和前言

      word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包.它简单.高效.因此引起了非常多人的关注. 因为 word2vec 的作者 Tomas ...

  5. db2 用户权限

        DB2数据库权限分为实例级权限(SYSADM.SYSCTRL.SYSMAINT.SYSMON)和DB2数据库级权限(DBAMD.LOAD).DB2中用户所拥有的权限主要考虑三个方面:实例级.数 ...

  6. 486E - LIS of Sequence(LIS)

    题意:给一个长度为n的序列.问每一个数关于序列的LIS(longest increasing subsequence)是什么角色. 这里分了三种: 1.此数没有出如今随意一条LIS中 2.此数出如今至 ...

  7. Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: ...

  8. 解决Java compiler level does not match the version of the installed Java project facet.问题

    其实之前遇到过Java compiler level does not match the version of the installed Java project facet.这个问题,因为当时没 ...

  9. 模拟产生CBC LATCH与buffer busy wait等待事件

    数据库版本:11.2.0.4.0 1.查出表TEST相关信息 select rowid, dbms_rowid.rowid_row_number(rowid) rowid_rownum, dbms_r ...

  10. DELPHI XE7 新的并行库

    DELPHI XE7 的新功能列表里面增加了并行库System.Threading, System.SyncObjs. 为什么要增加新的并行库? 还是为了跨平台.以前要并行编程只能从TThread类继 ...