【问题标题】:Properly overriding WndProc正确覆盖 WndProc
【发布时间】:2018-04-26 10:54:52
【问题描述】:

一天前,我开始重写我的一个旧组件,我决定提高它的可读性。 我的组件是一个典型的 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 以便能够使用在过程中分组的代码并能够仅针对某些消息调用原始窗口过程?

【问题讨论】:

  • 要么使用嵌套函数,要么使用message 指令。
  • Unfortunately Inherited word in these procedures doesn't work anymore你还记得override WndProc吗?
  • 不是@Vasek。 Asker 想调用继承的 WndProc。从被覆盖的 WndProc 中这很好,但不是从其他方法中。
  • 调用DefaultHandler 就足够了,我会说。
  • @Victoria,答案已经在这里,但您使用DefaultHandler 的建议让我获得了更多关于 Delphi 中消息处理的信息。谢谢!

标签: delphi controls wndproc


【解决方案1】:

正如 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;

【讨论】:

  • 嗯,以这种方式处理消息是真正的技巧(对我来说)。昨天David 给了我一个使用相同技术的链接。不幸的是,他没有提供评论作为答案,所以我会接受你的回答。谢谢!
【解决方案2】:

从 WMWINDOWPOSCHANGED 调用继承的 WndProc 将调用继承的 WndProc。所以你可以这样做:

procedure WMWINDOWPOSCHANGED(var Message: TMessage)
begin
  // call inherited WndProc if you need to
  inherited WndProc(Message);
  .. do you own processing
end;

【讨论】:

  • 是的,您的解决方案完成了这项工作。但是对不起,RM,我接受了Remy 的回答,因为它的实现很优雅。感谢您提供有用的想法!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 1970-01-01
  • 2016-10-19
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多