0

我正在使用 WMSysCommand 消息来修改标题栏按钮(最大化/最小化)的行为,并且最近更新需要使用 WMNCHitTest,但由于代码冗长,我不想在乘法过程中拆分这两个相关消息。

我可以从其他消息中访问私人声明(消息)吗?如果我可以 - 怎么做?

  procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest) ;
  begin
    SendMessage(Handle, HTCAPTION, WM_NCHitTest, 0); // or other wParam or lParam ???? 
  end;

  procedure TForm1.WMSysCommand;
  begin
    if (Msg.CmdType = SC_MAXIMIZE or 61488) or (Msg.Result = htCaption or 2) then // if command is Maximize or reciever message of Caption Bar click
    begin
      if CheckWin32Version(6, 0) then
        Constraints.MaxHeight := 507
      else
        Constraints.MaxHeight := 499;
      Constraints.MaxWidth := 0;
    end
    else if (Msg.CmdType = SC_MINIMIZE or 61472) or (Msg.Result = htCaption or 2) then // if command is Minimize
    begin
      if (EnsureRange(Width, 252, 510) >= (510 / 2)) then
        PreviewOpn.Caption := '<'
      else
        PreviewOpn.Caption := '>';
    end;
    DefaultHandler(Msg); // reset Message handler to default ( Application )
  end;

Soo ...我是正确地认为并且只是不知道正确的命令还是我在想完全胡说八道?

问候。谢谢你的帮助...

4

1 回答 1

4

您的代码和文本表明您对消息处理程序的工作方式存在一些误解。首先,您询问有关访问私人消息处理程序的问题。您不需要从父类访问私人消息处理程序。无论父类是否处理该消息,您都可以覆盖任何消息的处理程序。只需编写您的消息处理程序。即使父处理程序是私有的,它也会自动覆盖父处理程序。(事实上​​,这就是为什么我们经常将消息处理程序声明为私有的原因——后代总是可以覆盖它们,并且由于没有理由直接调用它,因此没有理由将其公开。)

看起来您正试图通过调用来获取基类的消息处理行为DefaultHandler。这有时会起作用,但只是偶然。DefaultHandler转到基类的消息处理程序。如果基类和您的后代之间还有其他类,则调用DefaultHandler将跳过它们的处理程序。使用指令代替该函数,inherited就像覆盖普通方法一样。

当您希望您的对象表现得好像已向其发送了一条消息时,您不必总是使用SendMessage. 相反,您可以调用对象的Perform方法。将发生所有相同的消息调度操作,但您可以跳过 Windows 消息队列。

如果您有两种方法应该执行许多类似的任务,那么您有几个选择:

  1. 复制并粘贴代码,使两个函数看起来相似。
  2. 将所有代码放在一个函数中,然后从第二个函数调用它。
  3. 将所有代码放在一个新的第三个函数中,然后从两个函数中调用它。

第一个选项通常不是一个好主意。如果保证第一个函数始终是第二个函数的子集,则第二个选项可能很好。但是,如果它需要做一些第二个函数并不总是想要的事情,那么从第二个函数调用它是不合适的。第三种选择是罗伯特的回答所暗示的。

如果我的水晶球工作正常,第二个选项可能是您需要的。我想你希望你的 wm_SysCommand 处理程序做一些命中测试,所以你想调用wm_NCHitTest消息处理程序。这很容易。

procedure TForm1.WMSysCommand;
var
  Hit: DWord;
begin
  Hit := Perform(wm_NCHitTest, ...);
  if (Msg.CmdType = SC_MAXIMIZE) or (Hit = htCaption) then // if command is Maximize or reciever message of Caption Bar click
  begin
    if CheckWin32Version(6, 0) then
      Constraints.MaxHeight := 507
    else
      Constraints.MaxHeight := 499;
    Constraints.MaxWidth := 0;
  end
  else if (Msg.CmdType = SC_MINIMIZE) or (Hit = htCaption) then // if command is Minimize
  begin
    if (EnsureRange(Width, 252, 510) >= (510 / 2)) then
      PreviewOpn.Caption := '<'
    else
      PreviewOpn.Caption := '>';
  end;
  inherited;
end;

请注意我对您的代码所做的一些更改。首先,我使用Perform调用对象的 wm_NCHitTest 处理程序,并将结果存储在一个变量中。我在接下来的条件中使用该变量来检查鼠标点击的位置。其次,我or从您的条件中删除了测试。您将命名常量与其数字等价物结合起来,这是毫无意义且令人困惑的。第三,我DefaultHandler用 one to 替换了调用inherited

Beware, though: The wm_SysCommand message is sent for keyboard messages as well as mouse messages. There won't always be a valid hit test. You're probably going about this sys-command handler all wrong, but it's hard to tell what you're really after.

于 2010-06-14T14:31:44.200 回答