正确覆盖 WndProc
Properly overriding WndProc
一天前,我开始重写我的一个旧组件,我决定提高它的可读性。
我的组件是一个典型的 TWinControl
,它覆盖了 WndProc
来处理我自己的很多消息。每条消息代码太多,看代码成了我的难题
因此,为了寻找改进 WndProc
内代码的解决方案,我将这些大块代码组织在程序中,每次在 WndProc
中传递适当的消息时调用这些程序。这就是现在的样子:
procedure TMyControl.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_WINDOWPOSCHANGED:
WMWINDOWPOSCHANGED(Message);
WM_DESTROY:
WMDESTROY(Message);
WM_STYLECHANGED:
WMSTYLECHANGED(Message);
// lots of the same procedures for Windows messages
// ...
MM_FOLDER_CHANGED:
MMFOLDERCHANGED(Message);
MM_DIRECTORY_CHANGED:
MMDIRECTORYCHANGED(Message);
// lots of the same procedures for my own messages
// ...
else
Inherited WndProc(Message);
end;
end;
不幸的是 Inherited
这些程序中的单词不再起作用!
重要说明: 在某些 WM_XXX 消息中我没有调用 Inherited
来执行我自己对此类消息的处理,因此代码如下所示将分解我实现某些功能的努力。
procedure TMyControl.WndProc(var Message: TMessage);
begin
Inherited WndProc(Message);
case Message.Msg of
WM_WINDOWPOSCHANGED:
WMWINDOWPOSCHANGED(Message);
// further messages
// ...
end;
end;
我还想避免在每个消息 ID 之后插入 Inherited
,如下所示,因为它看起来很糟糕,而且我认为存在更优雅的方法来覆盖 WndProc
。
procedure TMyControl.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_WINDOWPOSCHANGED:
begin
Inherited WndProc(Message);
WMWINDOWPOSCHANGED(Message);
end;
// further messages
// ...
end;
end;
所以我的问题是:
如何正确覆盖 WndProc
以能够使用过程中分组的代码并能够仅为某些消息调用原始 window 过程?
从WMWINDOWPOSCHANGED 调用继承的WndProc 将调用继承的。所以你可以这样做:
procedure WMWINDOWPOSCHANGED(var Message: TMessage)
begin
// call inherited WndProc if you need to
inherited WndProc(Message);
.. do you own processing
end;
正如 RM 的回答所述,您的消息处理方法可以调用 inherited WndProc(Message)
而不仅仅是 inherited
,这样就可以正常工作。
但是,通过引入与它们正在处理的消息同名的方法,您公开了您正在处理的特定消息的知识。所以你可能会发现使用 Message Methods 而不是覆盖 WndProc
更容易,例如:
type
TMyControl = class(...)
private
procedure WMWindowPosChanged(var Message: TMessage); message WM_WINDOWPOSCHANGED;
procedure WMDestroy(var Message: TMessage); message WM_DESTROY;
procedure WMStyleChanged(var Message: TMessage); message WM_STYLECHANGED;
// and so on ...
end;
然后您的 message
方法可以根据需要调用 inherited
(或不调用),例如:
procedure TMyControl.WMWindowPosChanged(var Message: TMessage);
begin
inherited;
//...
end;
一天前,我开始重写我的一个旧组件,我决定提高它的可读性。
我的组件是一个典型的 TWinControl
,它覆盖了 WndProc
来处理我自己的很多消息。每条消息代码太多,看代码成了我的难题
因此,为了寻找改进 WndProc
内代码的解决方案,我将这些大块代码组织在程序中,每次在 WndProc
中传递适当的消息时调用这些程序。这就是现在的样子:
procedure TMyControl.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_WINDOWPOSCHANGED:
WMWINDOWPOSCHANGED(Message);
WM_DESTROY:
WMDESTROY(Message);
WM_STYLECHANGED:
WMSTYLECHANGED(Message);
// lots of the same procedures for Windows messages
// ...
MM_FOLDER_CHANGED:
MMFOLDERCHANGED(Message);
MM_DIRECTORY_CHANGED:
MMDIRECTORYCHANGED(Message);
// lots of the same procedures for my own messages
// ...
else
Inherited WndProc(Message);
end;
end;
不幸的是 Inherited
这些程序中的单词不再起作用!
重要说明: 在某些 WM_XXX 消息中我没有调用 Inherited
来执行我自己对此类消息的处理,因此代码如下所示将分解我实现某些功能的努力。
procedure TMyControl.WndProc(var Message: TMessage);
begin
Inherited WndProc(Message);
case Message.Msg of
WM_WINDOWPOSCHANGED:
WMWINDOWPOSCHANGED(Message);
// further messages
// ...
end;
end;
我还想避免在每个消息 ID 之后插入 Inherited
,如下所示,因为它看起来很糟糕,而且我认为存在更优雅的方法来覆盖 WndProc
。
procedure TMyControl.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_WINDOWPOSCHANGED:
begin
Inherited WndProc(Message);
WMWINDOWPOSCHANGED(Message);
end;
// further messages
// ...
end;
end;
所以我的问题是:
如何正确覆盖 WndProc
以能够使用过程中分组的代码并能够仅为某些消息调用原始 window 过程?
从WMWINDOWPOSCHANGED 调用继承的WndProc 将调用继承的。所以你可以这样做:
procedure WMWINDOWPOSCHANGED(var Message: TMessage)
begin
// call inherited WndProc if you need to
inherited WndProc(Message);
.. do you own processing
end;
正如 RM 的回答所述,您的消息处理方法可以调用 inherited WndProc(Message)
而不仅仅是 inherited
,这样就可以正常工作。
但是,通过引入与它们正在处理的消息同名的方法,您公开了您正在处理的特定消息的知识。所以你可能会发现使用 Message Methods 而不是覆盖 WndProc
更容易,例如:
type
TMyControl = class(...)
private
procedure WMWindowPosChanged(var Message: TMessage); message WM_WINDOWPOSCHANGED;
procedure WMDestroy(var Message: TMessage); message WM_DESTROY;
procedure WMStyleChanged(var Message: TMessage); message WM_STYLECHANGED;
// and so on ...
end;
然后您的 message
方法可以根据需要调用 inherited
(或不调用),例如:
procedure TMyControl.WMWindowPosChanged(var Message: TMessage);
begin
inherited;
//...
end;