【问题标题】:Accessing and inheriting Windows Message for other Windows Message in Delphi在 Delphi 中访问和继承其他 Windows 消息的 Windows 消息
【发布时间】:2010-06-14 13:02:38
【问题描述】:

我正在使用 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 ...我是正确地认为并且只是不知道正确的命令还是我在想完全废话*t?

问候。感谢您的帮助...

【问题讨论】:

  • 看起来您应该问的问题是:如何修改标题栏按钮的行为?
  • Wll - 不太好。最合适的做法是 - 如何从其他 WM 程序中模仿 WM ..."",但我没有输入它,因为它在某种意义上是黑客预定义了操作系统行为 ...不想在这里与版主进行一些严肃的交谈。

标签: delphi windows-messages


【解决方案1】:

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

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

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

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

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

第一个选项通常不是一个好主意。如果第一个函数保证始终是第二个函数的子集,则第二个选项可能很好。但是,如果它需要做一些第二个函数并不总是想要的事情,那么从第二个函数调用它是不合适的。第三个选项是Robert's answer 建议的。

如果我的水晶球工作正常,第二个选项可能是您需要的。我想你希望你的 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 调用替换为inherited

但请注意:wm_SysCommand 消息是针对 keyboard 消息和鼠标消息发送的。不会总是有有效的命中测试。你可能对这个 sys-command 处理程序的理解都错了,但很难说你真正想要的是什么。

【讨论】:

  • Rob, “当你希望你的对象表现得好像已经向它发送了一条消息时,你不必总是使用 SendMessage 向它发送一条消息。(...)”但是什么如果我在带有 ProcessMessages 命令的循环中使用它会发生什么?这是否意味着 Perform() 实际上将充当独家 SendMesssage() ?哦 - 数字等于只是为了让我自己记住这些该死的数字,用于内部和外部异常处理和 WER 处理......实际上 - 我总是可以通过 Ord() 检查 Keys 代码,所以我不认为这将是一个大问题......
  • ProcessMessages 与它无关。 Perform 对于在没有窗口句柄的对象上调用消息处理程序也很有用。
猜你喜欢
  • 1970-01-01
  • 2015-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
  • 1970-01-01
  • 2021-01-28
  • 2014-03-04
相关资源
最近更新 更多