Правильно перекрывающий WndProc - PullRequest
0 голосов
/ 26 апреля 2018

Однажды назад я начал переписывать один из моих старых компонентов и решил улучшить его читабельность. Мой компонент - это типичный 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;

Я также хочу не вставлять 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, чтобы иметь возможность использовать код, сгруппированный в процедурах, и иметь возможность вызывать исходную оконную процедуру только для некоторых сообщений?

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Как указано в ответе RM, ваши методы обработки сообщений могут вызывать inherited WndProc(Message) вместо inherited, и это будет нормально работать.

Однако, вводя методы с теми же именами, что и сообщения, которые они обрабатывают, вы раскрываете знания о конкретных сообщениях, которые вы обрабатываете. Поэтому вам может быть проще использовать Методы сообщений вместо переопределения 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;
0 голосов
/ 26 апреля 2018

Вызов унаследованного WndProc из WMWINDOWPOSCHANGED вызовет унаследованный. Таким образом, вы можете сделать это так:

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